Skip to content
Blog

Back up a FiveM server and database, and test the restore

mysqldump for oxmysql, server files, encryption, a weekly restore test, and how to give one player their inventory back without rolling back the city.

By Termi

10 min read
  • Backups
  • Database
  • oxmysql
On this page

To back up a FiveM server, dump the MySQL or MariaDB database that oxmysql connects to with mysqldump --single-transaction, archive server.cfg, your resources and txData, encrypt both, and copy them off the machine. A backup only counts once you have restored it, so load one into a throwaway database every week. To give one player back their inventory, restore into that throwaway database and copy only their rows.

This guide does all of that by hand with free tools, on Linux or on Windows with Git Bash. Nothing in it needs FiveDock. At the end, the same thing done for you, including Deploy Guard, which takes a backup before every restart.

What a FiveM backup has to include

  • The database. Characters, money, inventories, vehicles, houses, phone messages: everything ESX, QBCore, Qbox and ox_inventory keep lives here. It changes every minute, so it needs the most frequent backup.
  • server.cfg. Your resource order, convars, permissions, the database password and your sv_licenseKey.
  • resources. Your scripts, maps and vehicles, including every change you made to scripts you bought.
  • txData. txAdmin’s settings, admins and player history.

Leave out cache: FXServer rebuilds it on the next start, and it is often the largest folder on the disk. Logs can go too.

Find the database oxmysql uses

oxmysql reads its connection from server.cfg:

server.cfg
set mysql_connection_string "mysql://fivem:[email protected]/fivem?charset=utf8mb4"

That is user fivem, password secret, host 127.0.0.1 and database fivem. Some servers use the older form server=127.0.0.1;database=fivem;userid=fivem;password=secret, which holds the same four values.

Dump the database with mysqldump

Put the credentials in a file only you can read, so the password is not visible in the process list or your shell history:

bash
cat > "$HOME/.fivem-backup.cnf" <<'EOF'
[client]
user=fivem
password=secret
host=127.0.0.1
EOF
chmod 600 "$HOME/.fivem-backup.cnf"

Then dump the database while the server keeps running:

bash
mysqldump --defaults-extra-file="$HOME/.fivem-backup.cnf" \
  --single-transaction --quick --no-tablespaces \
  --default-character-set=utf8mb4 --hex-blob \
  fivem | gzip > "fivem-$(date +%F-%H%M).sql.gz"
  • --single-transaction reads every InnoDB table in one consistent snapshot without locking it, so players keep playing and the money in users matches the items in ox_inventory.
  • --quick streams rows instead of loading whole tables into memory, which matters once logs and phone tables reach millions of rows.
  • --no-tablespaces avoids a privilege error on MySQL 8 (see the errors).
  • --default-character-set=utf8mb4 and --hex-blob keep emoji in character names and binary columns intact.

On MariaDB the same command is also called mariadb-dump, with the same options. If your scripts use stored procedures, add --routines.

Check for MyISAM tables

The snapshot only covers InnoDB tables. A MyISAM table is read at a slightly different moment from the rest, so a backup taken during a trade can hold the money from before it and the item from after. ALTER TABLE name ENGINE=InnoDB; converts one.

Back up the server files

bash
tar -czf "files-$(date +%F-%H%M).tar.gz" \
  --exclude='server-data/cache' \
  -C /home/fivem server-data txData

Point -C at the folder that holds server-data and txData. On Windows, tar ships with Windows 10 and 11 and takes the same options.

Encrypt it before it leaves the machine

A database dump holds every player’s identifiers, and server.cfg holds the database password and your license key. Anyone who gets a copy can read all of it, or start your server under your key. Encrypt with age and a public key: the server can encrypt backups but cannot open them, so a stolen server does not give away its own backups.

Make the key pair on your own computer, not on the server:

bash
age-keygen -o fivem-backup.key
# Public key: age1q9x...

Keep fivem-backup.key in your password manager and give the server only the public key that starts with age1:

bash
age -r age1q9x... -o fivem-2026-10-15-0400.sql.gz.age fivem-2026-10-15-0400.sql.gz

Lose the private key and every backup it encrypted is gone with it. Keep two copies, in two different places.

Keep copies off the server

A backup on the same disk goes when the disk fails, when the host ends your contract or when someone wipes the machine. Copy every backup to object storage, such as Backblaze B2, Cloudflare R2 or S3, with rclone. Give the server a storage key that can upload files but not delete them, so whoever gets into the server cannot delete your backups as well.

Run it every night

All of the above in one script:

backup.sh
#!/usr/bin/env bash
set -euo pipefail

STAMP=$(date +%F-%H%M)
OUT=/var/backups/fivem
RECIPIENT=age1q9x...
mkdir -p "$OUT"

mysqldump --defaults-extra-file="$HOME/.fivem-backup.cnf" \
  --single-transaction --quick --no-tablespaces \
  --default-character-set=utf8mb4 --hex-blob \
  fivem | gzip | age -r "$RECIPIENT" > "$OUT/db-$STAMP.sql.gz.age"

tar -czf - --exclude='server-data/cache' -C /home/fivem server-data txData \
  | age -r "$RECIPIENT" > "$OUT/files-$STAMP.tar.gz.age"

rclone copy "$OUT" b2:my-city-backups --include '*.age'
find "$OUT" -name '*.age' -mtime +14 -delete

set -o pipefail matters more than it looks. Without it, mysqldump | gzip succeeds whenever gzip does, so a wrong password leaves you a 20-byte file every night and a log that says everything worked. With it, the script stops at the first failure.

Run it at 04:00 every day with cron:

crontab -e
0 4 * * * /home/fivem/backup.sh >> /var/log/fivem-backup.log 2>&1

On Windows, run backup.sh with Git Bash from Task Scheduler. Take an extra backup by hand before every update to a framework or an inventory script.

Test the restore, or you do not have a backup

Most rollbacks fail on the night they are needed: the dump stopped halfway, the password changed three months ago, nobody kept the private key. A weekly test catches all three. Do it on a machine that has the private key and MySQL or MariaDB, such as your own computer or a test server:

bash
age -d -i fivem-backup.key db-2026-10-15-0400.sql.gz.age | gunzip > restore.sql
tail -n 1 restore.sql
# -- Dump completed on 2026-10-15  4:00:03

mysql -e 'DROP DATABASE IF EXISTS restore_test; CREATE DATABASE restore_test'
mysql restore_test < restore.sql

A complete dump ends with the -- Dump completed line. If it is missing, the dump was cut short. Once it is imported, compare the backup with the live server. Use players instead of users on QBCore and Qbox:

SQL
SELECT table_schema, COUNT(*) AS tables
FROM information_schema.tables
WHERE table_schema IN ('fivem', 'restore_test')
GROUP BY table_schema;

SELECT
  (SELECT COUNT(*) FROM fivem.users)        AS players_now,
  (SELECT COUNT(*) FROM restore_test.users) AS players_in_backup;

The same number of tables and a player count close to today’s means the backup is whole. To test the files too, unpack the archive next to a copy of FXServer, point it at restore_test and start it.

Roll back the whole server

Use this after a duplication exploit, a broken economy or an update that damaged the database. Every player loses what happened since the backup, so tell them first.

  1. Stop the server in txAdmin. Do not restart it: the framework saves every online player from memory on its timer and on the way out, and that would overwrite the restore.
  2. Take a backup of the broken state, in case the restore makes things worse.
  3. Import the backup from before the problem started.
  4. Start the server.
bash
mysqldump --defaults-extra-file="$HOME/.fivem-backup.cnf" \
  --single-transaction --quick --no-tablespaces \
  --default-character-set=utf8mb4 --hex-blob \
  fivem | gzip > before-rollback.sql.gz

age -d -i fivem-backup.key db-2026-10-15-0400.sql.gz.age | gunzip | mysql fivem

The dump drops and recreates each table it contains. A table created after the backup stays as it is.

Restore one player’s inventory without rolling back everyone

A player lost their inventory to a bug, or a cheater emptied their account. Rolling back the city would cost everyone else a day of play. Instead, import the backup into restore_test on the same database server, as in the restore test, and copy only that player’s rows back.

First find their identifier. In ESX it is the identifier column of users, and with ox_inventory their inventory is stored in the same row. In QBCore and Qbox it is citizenid in players. Then kick the player and keep them off the server until you are done, or the framework writes their current state back over the restore at its next save.

ESX

SQL
SET FOREIGN_KEY_CHECKS = 0;
START TRANSACTION;

REPLACE INTO fivem.users
  SELECT * FROM restore_test.users WHERE identifier = 'char1:3f2a9c...';

DELETE FROM fivem.owned_vehicles WHERE owner = 'char1:3f2a9c...';
INSERT INTO fivem.owned_vehicles
  SELECT * FROM restore_test.owned_vehicles WHERE owner = 'char1:3f2a9c...';

COMMIT;
SET FOREIGN_KEY_CHECKS = 1;

QBCore and Qbox

SQL
SET FOREIGN_KEY_CHECKS = 0;
START TRANSACTION;

REPLACE INTO fivem.players
  SELECT * FROM restore_test.players WHERE citizenid = 'KX81F2QD';

DELETE FROM fivem.player_vehicles WHERE citizenid = 'KX81F2QD';
INSERT INTO fivem.player_vehicles
  SELECT * FROM restore_test.player_vehicles WHERE citizenid = 'KX81F2QD';

COMMIT;
SET FOREIGN_KEY_CHECKS = 1;

REPLACE overwrites the player’s row with the one from the backup: money, inventory and position. The vehicles are deleted and inserted again, so a car bought after the backup goes too. If a car changed hands since the backup, the INSERT stops on a duplicate key and the transaction leaves everything as it was. Decide who keeps it, then run it again.

If the player traded since the backup, restoring them hands back what they already gave away, and the item now exists twice. Check their transactions before you restore someone who claims to have lost everything.

Errors you will probably hit

Access denied; you need the PROCESS privilege

mysqldump: Error: 'Access denied; you need (at least one of) the PROCESS privilege(s) for this operation' when trying to dump tablespaces appears on MySQL 8.0.21 and later. Add --no-tablespaces. A FiveM database has no tablespaces worth dumping.

Access denied when using LOCK TABLES

mysqldump: Got error: 1044: Access denied for user 'fivem'@'localhost' to database 'fivem' when using LOCK TABLES means the dump ran without --single-transaction and tried to lock every table. Add the option. It is also the reason the dump no longer freezes the server.

Unknown collation utf8mb4_0900_ai_ci

ERROR 1273 (HY000) at line 25: Unknown collation: 'utf8mb4_0900_ai_ci' means a MySQL 8 dump is going into MariaDB, which does not know that collation. Replace it before importing:

bash
sed -i 's/utf8mb4_0900_ai_ci/utf8mb4_unicode_ci/g' restore.sql

The same, done by FiveDock

Everything above is what FiveDock’s Time Machine does from inside your server, through the same agent that runs the rest of FiveDock. There is no script to maintain and no cron job to forget.

  • Encrypted with your key. The agent encrypts each backup on your machine with a key made for that server and shown to you once. We cannot read your backups, file names included, and a leaked server.cfg only opens that one server’s.
  • Consistent and incremental. Every table is read in one consistent snapshot, and the backup tells you which tables are MyISAM. Only the parts that changed are uploaded, and a deleted backup stays locked for 30 days so nobody can wipe your history.
  • Tested every week. FiveDock restores a backup into a throwaway database on your own server and marks it test-restored, so you find a broken backup weeks before you need it.
  • Rewind exactly what broke. The whole server, the database, one table, one resource, one file or one player, with a count of what will change before you confirm, and a safety backup first. It refuses to restore a player who is still connected, and refuses a database restore while ESX, QBCore or Qbox is running.
  • Deploy Guard. A backup before every restart, a verdict ten minutes after it that names the resource that caused trouble, and one click back to before the restart.
  • A backup when the economy breaks. When an economy alert fires, a backup is taken that second, before the damage spreads.

Every plan takes a daily backup. Restoring one table or one player, weekly test restores, hourly backups and Deploy Guard come with Metro. Pricing has the full list, and features shows the rest of Time Machine.

FAQ

How often should I back up a FiveM server?

Back up the database at least once a day, and once more by hand before every framework or inventory update. If your economy is busy, back up every hour: a duplication exploit found at 22:00 against a 04:00 backup costs every player 18 hours.

Can I back up the database while the server is running?

Yes. mysqldump --single-transaction reads InnoDB tables in one consistent snapshot without locking them, so players notice nothing. Only MyISAM tables fall outside the snapshot.

Does txAdmin back up my database?

No. txAdmin starts, restarts and watches the server, but it does not dump your MySQL or MariaDB database. Use mysqldump on a schedule, or a tool that does it for you.

How do I roll back a FiveM server after a dupe exploit?

Stop the server in txAdmin, take a backup of the current state, import the last backup from before the exploit and start the server again. If only a few players profited, restore or clean their rows instead of rolling back everyone.

How do I restore one player’s inventory?

Import the backup into a separate database on the same server, keep the player offline, and copy their rows from users (ESX) or players (QBCore and Qbox), plus their vehicles, into the live database in one transaction.

Where is the database oxmysql uses?

In server.cfg, on the set mysql_connection_string line. It holds the user, password, host and database name that mysqldump needs.

All articles