Backup & restore
mysqldump for logical backups, restoring, consistent dumps, binary logs and point-in-time recovery.
Disks fail, people run DELETE without WHERE, deployments go wrong and ransomware happens. A backup you can restore is the only cure. This lesson covers logical backups with mysqldump, restoring them, and point-in-time recovery with binary logs, plus the habits that make backups trustworthy.
Types of backup#
A solid strategy combines a regular full backup (daily or weekly) with continuous binary logs in between.
mysqldump basics#
mysqldump is a command-line program, so run it from your shell, not inside the mysql> prompt:
Important options:
The file is plain SQL: CREATE TABLE statements followed by multi-row INSERTs. Open one and look. It's reassuring to see your data there.
Compress and timestamp
Dumps compress very well. Pipe straight into gzip or zstd:
To run this unattended (from cron, for example), keep the credentials in a protected option file instead of on the command line:
The backup account needs only read-type privileges (RELOAD and REPLICATION CLIENT are needed for --source-data):
Restoring a dump#
A dump is just SQL, so restoring means running it with the mysql client:
From inside the mysql client, you can use source /path/to/shop_2026-09-30.sql; instead.
⚠️ Dumps contain
DROP TABLE IF EXISTSbefore eachCREATE TABLE. Restoring into a database replaces those tables. When in doubt, restore into a new database and copy over what you need.
Restoring a single table from a full dump: restore the whole dump into a scratch database, then copy the table back with INSERT INTO shop.orders SELECT * FROM scratch.orders .... (Or dump individual tables in the first place.)
Binary logs and point-in-time recovery#
The binary log records every change (inserts, updates, deletes, DDL) in order. It's on by default in MySQL 8:
Point-in-time recovery (PITR) means restoring the last full backup, then replaying the binary logs from the moment of that backup to just before the disaster.
Scenario: a dump ran at 02:00 with --source-data=2. At 15:42 someone ran DROP TABLE orders.
-
Find where the dump started. The position is written near the top of the file:
Terminal -
Find the bad statement in the binary log (use
--base64-output=DECODE-ROWS -vto read row events):TerminalThe
# at 21199969line just before it is the position where theDROPbegins. -
Restore the dump, then replay everything from the dump's position up to (but not including) the
DROP:Terminal
If the logs span several files, list them all in order on the mysqlbinlog command line. You can also stop by time with --stop-datetime="2026-10-01 15:42:00". With GTIDs enabled, --exclude-gtids lets you skip exactly the bad transaction. The workflow above was tested on MySQL 8.4: after replay, the rows inserted and updated after the dump were all back.
Keep binary logs long enough. binlog_expire_logs_seconds (default 30 days) controls retention. Logs older than your oldest restorable full backup are useless for PITR, and copying binlogs off the server (for example with mysqlbinlog --read-from-remote-server --raw --stop-never) protects them if the disk dies.
Other tools worth knowing#
- MySQL Shell (
mysqlsh) hasutil.dumpInstance(),util.dumpSchemas()andutil.loadDump(). They're parallel, compressed and much faster than mysqldump on large databases. (The oldermysqlpumptool was removed in MySQL 8.4.) - Percona XtraBackup takes hot physical backups of InnoDB: the standard for databases of hundreds of GB and up.
- Cloud snapshots (EBS, managed MySQL services) are convenient, but make sure they're crash-consistent and test them too.
SELECT ... INTO OUTFILE/LOAD DATA INFILEexport and import CSV data quickly (restricted bysecure_file_priv).
The backup rules that actually matter#
- 3-2-1: three copies, on two kinds of storage, with one off-site (another region or cloud account).
- Automate backups with cron or a systemd timer, and alert when one fails or is suspiciously small.
- Test restores regularly. Restore to a scratch server, run row counts and a smoke test, and time it. Your restore time is what matters during an outage.
- Protect backups: encrypt them and keep at least one copy where the production credentials can't delete it (ransomware deletes backups first).
- Back up before risky changes: migrations, bulk updates, upgrades.
- Document the procedure so a stressed colleague can follow it at 3 a.m.
What's next#
Next you'll store and query semi-structured data with MySQL's native JSON columns.
Check your understanding
Quick quiz
1.Why use
--single-transactionwhen running mysqldump on InnoDB tables?2.Your nightly dump ran at 02:00 and someone dropped a table at 15:42. What lets you recover the changes made between 02:00 and 15:42?
3.What is the only real proof that your backups work?
Finished reading?
Mark this lesson complete to track your progress.