$ dbaguide.com / cheat-sheets / mysql-backup-recovery

MySQL Backup & Recovery Reference

Production guide to mysqldump, MySQL Shell, XtraBackup, binlog archiving, PITR and disaster scenarios

MySQL 8.0 / 8.4 LTS
Updated: October 2026 · Production-grade
RPO
How much data? · acceptable loss
RTO
How fast? · time to restore
Rule
3-2-1-1-0 · 3 copies, 2 media, 1 off-site
+1 / +0
immutable · 0 restore-test errors
Golden Rule
An untested backup = no backup
01

Fundamentals & Strategy

ConceptDescription
LogicalSQL / object-level dump. Version & platform independent, easy selective restore; slow restore on large data (indexes are rebuilt).
PhysicalBlock copy of the data files. Fast restore, fits TB scale; requires same major version + platform.
SnapshotLVM / ZFS / EBS / SAN snapshot. Crash-consistent; safe if WAL/redo is on the same volume or backup mode is used.
Full / Incr / DiffEverything / changes since last backup / since last full. The longer the incremental chain, the higher restore time and risk.
Hot / Warm / ColdReads+writes allowed / reads only / server stopped. Production target: hot.
Continuous ArchiveFull backup + continuous binlog stream → PITR: return to any moment. Brings RPO down to seconds.
Choosing a Method
ScenarioRecommendation
< 100 GB, version migration, single schemautil.dumpSchemas / mydumper
TB scale, short RTOXtraBackup / MEB + binlog
RPO in secondsSemi-sync replica + binlog stream
"I deleted it by mistake" protectionPITR + SOURCE_DELAY
Tool Map
Logicalmysqldump · MySQL Shell util.* · mydumper
PhysicalXtraBackup · MEB (mysqlbackup) · CLONE
Binlogmysqlbinlog · SHOW BINARY LOGS
InnoDB OnlyHot physical backup and consistent dumps are guaranteed only for InnoDB
Replication is not a backup: DROP TABLE or a bad UPDATE reaches every replica within milliseconds. HA ≠ DR.
02

Logical Backup

ToolParallelNote
mysqldump✗Available everywhere; single thread, small/medium data
mysqlpump✓deprecated in 8.0.34, removed in 8.4 — avoid
Shell util.*✓dumpInstance / dumpSchemas / dumpTables + loadDump; zstd, chunking, resume
mydumper✓Open source, parallel restore with myloader
mysqldump — Production Flags
$ mysqldump --single-transaction --source-data=2 \ --routines --events --triggers --hex-blob \ --set-gtid-purged=ON --all-databases \ | zstd -T0 > /bk/full_$(date +%F).sql.zst # --source-data=2 → binlog position written as a comment # (before 8.0.26: --master-data=2)
MySQL Shell Dump & Load (JS)
util.dumpInstance('/bk/inst_2026-10-13', {threads: 8, compression: 'zstd', consistent: true}) util.dumpSchemas(['shop'], '/bk/shop', {threads: 8}) // target needs local_infile=ON util.loadDump('/bk/inst_2026-10-13', {threads: 8, deferTableIndexes: 'all'})
Restore
$ zstd -dc full.sql.zst | mysql -u root -p $ myloader -d /bk/mydumper -t 8 --overwrite-tables
Caution: --single-transaction is consistent only for InnoDB; MyISAM tables stay inconsistent. Do not run DDL (ALTER/TRUNCATE) during the dump — it breaks consistency.
Speed: Shell util.loadDump and myloader are much faster than a plain SQL restore: they load in parallel and build indexes last.
03

Physical Backup

ToolLicenseNote
XtraBackupGPLHot, full + incremental, stream (xbstream), compression, encryption
MEBEnterprisemysqlbackup: image backup, incremental, TDE support
CLONEBuilt-in8.0.17+: CLONE LOCAL DATA DIRECTORY — local physical copy
XtraBackup — Full + Incremental
$ xtrabackup --backup --target-dir=/bk/full $ xtrabackup --backup --target-dir=/bk/inc1 \ --incremental-basedir=/bk/full # PREPARE: --apply-log-only on all but the last incremental $ xtrabackup --prepare --apply-log-only --target-dir=/bk/full $ xtrabackup --prepare --target-dir=/bk/full \ --incremental-dir=/bk/inc1 # RESTORE: empty datadir, server stopped $ xtrabackup --copy-back --target-dir=/bk/full $ chown -R mysql:mysql /var/lib/mysql
Stream → Remote Server / Object Storage
$ xtrabackup --backup --stream=xbstream --compress \ --parallel=4 | ssh bk01 "xbstream -x -C /bk/db1"
Local Copy with CLONE & MEB
INSTALL PLUGIN clone SONAME 'mysql_clone.so'; CLONE LOCAL DATA DIRECTORY = '/bk/clone_20261013'; $ mysqlbackup --backup-dir=/bk/meb \ --backup-image=full.mbi backup-to-image
Position Infoxtrabackup_binlog_info → binlog file, position and GTID set — the starting point for PITR.
Caution: The XtraBackup version must match the server (8.0 ↔ 8.0, 8.4 ↔ 8.4). An unprepared backup cannot be restored — test the prepare step right after taking the backup.
MySQL Backup & Recovery Reference · Binlog PITR, Verification & Disaster Scenarios
04

Binlog & Point-in-Time Recovery

Critical
ParameterRecommended
log_binON (8.0+ default)
binlog_formatROW
sync_binlog1 — to disk on every commit
innodb_flush_log_at_trx_commit1 — full durability
binlog_expire_logs_seconds≥ age of the oldest backup
gtid_modeON + enforce_gtid_consistency
Live Binlog Backup (on a separate server)
$ mysqlbinlog --read-from-remote-server --raw \ --stop-never --host=db1 --user=bkp -p \ --result-file=/binlogs/ binlog.000001
Step by Step PITR
1Restore the full backup (dump / XtraBackup / CLONE).
2Find the start position: dump header or xtrabackup_binlog_info.
3Find the position of the bad event (below).
4Replay binlogs in a single command up to just before the event.
Find the Event & Replay
$ mysqlbinlog -v --base64-output=DECODE-ROWS \ --start-datetime="2026-10-13 09:50:00" binlog.000043 \ | grep -n -B5 -i "DROP TABLE" # → end_log_pos $ mysqlbinlog --start-position=157 --stop-position=48211 \ binlog.000042 binlog.000043 | mysql -u root -p # With GTID: skip the bad transaction, replay the rest $ mysqlbinlog --exclude-gtids='3E11FA47-…:1234' \ binlog.000042 binlog.000043 | mysql -u root -p
Trap: Do not replay binlog files one by one with mysqlbinlog | mysql — temporary tables and transactions spanning files break. Pass them all in one call.
05

Verification, Testing & Monitoring

CheckTool / Method
Backup Integrityxtrabackup --prepare → "completed OK!", MEB validate
Data IntegrityCHECK TABLE, mysqlcheck, CHECKSUM TABLE
Replica Consistencypt-table-checksum → if drift found pt-table-sync
Binlog Healthbinlog stream process, SHOW BINARY LOGS, gtid_purged
Restore TestAutomated, at least weekly; restore on a separate server → validate with queries → measure RTO and record it.
Binlog Health Check
SHOW BINARY LOGS; SHOW BINARY LOG STATUS; -- 8.4 (8.0: SHOW MASTER STATUS) SELECT @@gtid_executed, @@gtid_purged, @@binlog_expire_logs_seconds;
Integrity Checks
$ mysqlcheck --all-databases --check -u root -p $ mysqlbackup --backup-image=/bk/full.mbi validate $ pt-table-checksum --replicate=percona.checksums h=db1 CHECKSUM TABLE shop.orders;
Set Up Alerts
Age of last successful backup > 26 hoursCritical
Binlog stream process down / lag > RPOCritical
Binlog purged before the next backupCritical
Sudden ±30% change in backup sizeImportant
Backup disk usage > 80%Important
MySQL 8.4: SHOW MASTER STATUS was removed → use SHOW BINARY LOG STATUS (8.2+). Update monitoring scripts before upgrading.
06

Disaster Scenarios & Checklist

ScenarioSolution
Accidental DROP / DELETEBinlog PITR (--stop-position / --exclude-gtids) or pull the table from a delayed replica
Disk / server lossFail over to a replica → new replica: CLONE INSTANCE FROM
RansomwareImmutable (object lock) off-site copy + xtrabackup --encrypt + separate credentials
Corrupt pageCHECK TABLE detects it → restore from backup; last resort innodb_force_recovery
Region lossInnoDB ClusterSet / cross-region backup copy + DR runbook
Delayed Replica (1 hour)
STOP REPLICA SQL_THREAD; CHANGE REPLICATION SOURCE TO SOURCE_DELAY = 3600; START REPLICA SQL_THREAD; -- during an incident: apply up to just before the bad GTID START REPLICA SQL_THREAD UNTIL SQL_BEFORE_GTIDS = '3E11FA47-…:1234';
RPO / RTO documented and signed off by the businessSLA → method choiceCritical
Binlog archiving enabled and monitoredsync_binlog=1 · mysqlbinlog --stop-neverCritical
Automated restore testweekly · RTO measurementCritical
Off-site + encrypted copyxtrabackup --encrypt · S3 object lockCritical
Retention policy enforcedbinlog_expire_logs_seconds ≥ backup ageImportant
Users & grants backed uputil.dumpInstance · SHOW CREATE USER / SHOW GRANTSImportant
Config files version-controlledmy.cnf · mysqld-auto.cnf (SET PERSIST)Recommended
DR runbook current and rehearsed2 drills per yearRecommended
Critical now Important this quarter Recommended plan it