Introduction
A FiveM server is two things: files (resources, server.cfg, txData) and the MySQL DB (identifiers, economy, characters). Both must be backed up coherently. A files-only backup without the DB = nearly useless for an RP/economy server.
Prerequisites
- A FiveM server at VeryCloud (Wisp panel)
- An associated MySQL DB (local or external)
- Optional: external VPS for offsite
Step 1: What to back up
| Element | Importance | Method |
|---|---|---|
/resources/ | Critical | Wisp Backup or SFTP |
/server.cfg | Critical | Wisp Backup |
/txData/ (txAdmin) | Critical | Wisp Backup |
| MySQL DB | Critical | Separate mysqldump |
| Logs | Optional | GDPR-dependent |
| FiveM cache | Useless | Exclude (regenerable) |
Step 2: Wisp schedule for files
In Wisp → Schedules:
- Create Schedule
- Name:
Daily files backup 3 AM - Cron:
0 3 * * * - Only when online: yes
- Add Task: Create Backup, name
daily-{date}
Wisp snapshots /home/container/ (resources + config + txData).
Step 3: MySQL backup with mysqldump
Wisp does NOT back up the DB (it's external to the FiveM container). Do it yourself.
On your MySQL server (or external VPS with remote access):
#!/bin/bash
set -e
DB_HOST="your.mysql.host"
DB_USER="fivem_backup_user"
DB_PASS_FILE="/root/.mysql_pass" # chmod 600
DB_NAME="fivem_db"
DEST="/backups/mysql"
mkdir -p "$DEST"
DATE=$(date +%Y%m%d_%H%M%S)
FILE="$DEST/fivem_${DATE}.sql.gz"
mysqldump \
-h "$DB_HOST" -u "$DB_USER" -p"$(cat $DB_PASS_FILE)" \
--single-transaction --quick --lock-tables=false \
--routines --triggers --events \
"$DB_NAME" | gzip > "$FILE"
echo "Backup: $FILE ($(du -h $FILE | cut -f1))"
# Rotate: keep 14 days
find "$DEST" -name "fivem_*.sql.gz" -mtime +14 -delete
Cron:
0 2 * * * /usr/local/bin/mysql-backup-fivem.sh >> /var/log/mysql-backup.log 2>&1
--single-transaction is essential to avoid locking the DB.
Step 4: Dedicated backup MySQL user
Minimal privileges:
CREATE USER 'fivem_backup_user'@'IP_BACKUP_HOST' IDENTIFIED BY 'solid_pass';
GRANT SELECT, SHOW VIEW, LOCK TABLES, EVENT, TRIGGER ON fivem_db.* TO 'fivem_backup_user'@'IP_BACKUP_HOST';
FLUSH PRIVILEGES;
No DROP, no INSERT — read-only.
Step 5: Offsite with rclone
On the backup VPS:
# One-time config
rclone config
# Daily sync
rclone sync /backups/mysql b2:mybucket/fivem-mysql \
--transfers 4 \
--backup-dir b2:mybucket/fivem-old/$(date +%F)
Cron:
30 4 * * * rclone sync /backups/mysql b2:mybucket/fivem-mysql --transfers 4
Step 6: Test a restore
Monthly. On a staging:
Restore files:
- Create a staging FiveM server
- Wisp → Backups → restore the latest backup to that env
Restore DB:
gunzip < /backups/mysql/fivem_20260516_020000.sql.gz > /tmp/restore.sql
mysql -h STAGING_DB_HOST -u staging_user -p staging_db < /tmp/restore.sql
Start the staging server, verify players/vehicles/houses are there.
Step 7: Incident restore procedure
Scenario: prod compromised or data lost.
Step 1 — Communicate — Announce immediate maintenance in Discord/Twitter. Block reconnections.
Step 2 — Identify restore point — Last backup BEFORE the problem. 5 min to think.
Step 3 — Restore files — Wisp → Backups → restore.
Step 4 — Restore DB:
mysql -h DB_HOST -u root -p
DROP DATABASE fivem_db;
CREATE DATABASE fivem_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
exit
gunzip < /backups/mysql/fivem_GOOD_DATE.sql.gz | \
mysql -h DB_HOST -u root -p fivem_db
Step 5 — Restart + verify — Start server, check logs, validate (connect in-game, look at a known character).
Step 6 — Communicate return.
Step 8: Backups before major changes
Before:
- Framework update (ESX, QBCore)
- Importing custom scripts
- DB schema change
- FiveM artifacts update
→ Manual snapshot Wisp + manual MySQL dump.
mysqldump -u user -p --single-transaction db_name | gzip > manual_$(date +%F_%H%M).sql.gz
Step 9: 3-2-1 recap
- 3 copies: Wisp local + backup VPS + cloud (B2/S3)
- 2 media: Wisp + your external VPS
- 1 offsite: remote cloud
€5-10/month in cloud storage protects hundreds of hours of accumulated gameplay.
Step 10: Monitor backups
You want to know if a backup failed:
- Healthchecks.io: ping after each OK backup
- Discord webhook: success/failure notification
- Mail alert if no backup for >25h
Discord webhook in script:
curl -X POST -H "Content-Type: application/json" \
-d "{\"content\":\"MySQL backup OK: ${FILE}\"}" \
https://discord.com/api/webhooks/.../...
Troubleshooting
mysqldump: Got error: 1142: SELECT, LOCK TABLES command denied — backup user lacks LOCK TABLES. GRANT LOCK TABLES. Or use --lock-tables=false (combined with --single-transaction).
Huge backup (several GB) — logs or cache tables too big. Truncate before backup. Enable framework log rotation.
DB restore fails mid-stream — schema mismatch (collation, MySQL version). Verify same MySQL version staging/prod.
Wisp backup hits quota — scale plan or reduce retention. Exclude cache (cache/ is regenerable).
Useful commands
mysqldump --single-transaction db | gzip > db.sql.gz
du -sh /backups/
gunzip < backup.sql.gz | mysql db
gunzip -t backup.sql.gz
Conclusion
Complete FiveM backup = Wisp Schedules (files) + mysqldump cron (DB) + cloud offsite. 3 independent levels, retested monthly, sleep tight. Classic trap = backing up only Wisp and forgetting the DB. An RP economy disappearing = your community leaving.
Going further: full CI automation, healthchecks + Discord/Slack alerting, dedup with restic to optimize storage.


















