How to back up a MySQL Docker container (2026)
The correct way to back up a MySQL container is a logical dump, not a file copy. Run `mysqldump --all-databases --single-transaction --routines --triggers -uroot -p"$MYSQL_ROOT_PASSWORD"` inside the container and back up its output. Copying /var/lib/mysql while MySQL is writing produces an inconsistent snapshot; --single-transaction wraps the dump in one InnoDB transaction, capturing every table at a single consistent point without a write lock.
What Dockstash detects
| Env keys detected | MYSQL_ROOT_PASSWORD, MYSQL_DATABASE, MYSQL_USER, MYSQL_PASSWORD |
|---|---|
| Default port | 3306 |
| Live data paths (never copied live) | /var/lib/mysql |
| Example images | mysql:8, mysql:8.0, mysql:5.7, mysql |
Back up MySQL with Dockstash, step by step
Create your Dockstash account and open the dashboard
Sign up free at app.dockstash.com/register. The one-time setup wizard asks for your storage VPS (the machine that will hold the encrypted backups) and generates an encryption password — save that password in a password manager immediately, it is shown exactly once.
Add the Docker project that runs MySQL
On the Projects screen Dockstash auto-detects every Compose project folder on the server (by default under /var/www). Pick the project that contains your MySQL service. Nothing is backed up yet — you are just telling Dockstash where the project lives.
Check that MySQL was detected
Open the project and look at the Plan tab. Dockstash reads docker-compose.yml, recognizes the mysql image, and adds a database layer with the right dump command — plus the container name it resolved and the env keys it found (MYSQL_ROOT_PASSWORD, MYSQL_DATABASE, MYSQL_USER, MYSQL_PASSWORD). You can toggle files, databases, and proxy configs on or off before saving.
Optional: sanity-check the dump by hand
If you want proof before automating, run the same dump Dockstash will run. You should see SQL stream out — CREATE DATABASE, CREATE TABLE, and INSERT statements. That output is what gets backed up, never the live /var/lib/mysql directory.
docker exec <mysql-container> sh -c 'mysqldump --all-databases --single-transaction -uroot -p"$MYSQL_ROOT_PASSWORD"' | head -n 20Confirm your storage destination
Backups are stored as encrypted restic snapshots on your own storage VPS over SSH. If you completed the setup wizard this is already configured; you can change host, user, port, or the SSH key any time under Settings → Storage.
Set a backup schedule
On the project’s Schedule tab pick daily, weekly, or a custom cron expression (validated inline). Daily at a quiet hour is the right default for most MySQL projects. Add a weekly prune schedule with your retention policy so old snapshots are trimmed automatically.
Run the first backup now
Click Backup Now on the project card. Dockstash executes mysqldump with --single-transaction, --routines, and --triggers inside the running container and streams the dump straight into restic — you can watch the live restic output line by line in the log panel while it runs.
Confirm the snapshot exists
When the run finishes, the project card shows the new last-backup time, snapshot count, and repository size. Open the Snapshots screen and you will see the restore point in the timeline — that is your proof the backup landed off-site.
The dump command
mysqldump --all-databases --single-transaction --routines --triggers -uroot -p"$MYSQL_ROOT_PASSWORD"The restore command
mysql -uroot -p"$MYSQL_ROOT_PASSWORD"--single-transaction wraps the dump in one InnoDB transaction, capturing every table at a single consistent point without a write lock.
Restore a MySQL backup and prove it works
A MySQL backup is only real once it has restored. Dockstash restores never overwrite your live database by default — you restore to a fresh location first, check the data, and promote it deliberately.
Pick a restore point
Open Snapshots, select the project, and browse the timeline of restore points. Each row is a complete single-point-in-time dump of every database on the server — schemas, data, routines, and triggers — plus the project files captured in the same run.
Restore to a new location
Click Restore and keep the default "Restore to new location" mode. Type the project name to confirm — this is a deliberate, typed-confirm action. The dump and files land in the target path you choose, leaving the live project untouched.
Verify the restored data
Load the restored dump into a scratch MySQL container, then run SHOW DATABASES to confirm every schema came back, and spot-check the tables your app depends on. Row counts and recent records are the quickest truth test.
docker exec <mysql-container> sh -c 'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "SHOW DATABASES;"'Promote when satisfied
Once the restored data checks out, point your app at it (or repeat the restore with "Overwrite existing" — an explicit opt-in). Better: let the weekly restore drill do this proof automatically so a restore is never your first rehearsal.
Gotchas to avoid
- Never restic the live /var/lib/mysql directory — InnoDB tablespaces copied mid-write are inconsistent and will fail recovery.
- --single-transaction only gives a consistent snapshot for transactional (InnoDB) tables; MyISAM tables are not covered and need a lock.
- Add --routines and --triggers or stored procedures and triggers are silently dropped from the dump.
Common MySQL backup problems
- Symptom
- The dump fails with "Access denied for user 'root'@'localhost'".
- Cause
- The MYSQL_ROOT_PASSWORD in compose no longer matches the password inside the data volume — the env var only sets the password on first initialization, so changing it later in compose does nothing to an existing volume.
- Fix
- Use the password the volume was initialized with, or reset the root password inside the container, then align the compose env so detection and the dump agree.
- Symptom
- The dump completes but some tables are inconsistent after restore.
- Cause
- Those tables are MyISAM. --single-transaction only guarantees a consistent snapshot for transactional InnoDB tables; MyISAM tables are read outside that guarantee.
- Fix
- Check the engine with SHOW TABLE STATUS. Migrate MyISAM tables to InnoDB (ALTER TABLE ... ENGINE=InnoDB) — the durable fix — or accept a brief lock with --lock-tables for those tables.
- Symptom
- Restore into a scratch container errors with "Unknown collation: utf8mb4_0900_ai_ci".
- Cause
- The dump came from MySQL 8.x but you are restoring into a 5.7 image; 8.0 default collations do not exist in older servers.
- Fix
- Restore into the same major version the dump came from (e.g. mysql:8). Restoring older dumps into newer servers works; the reverse frequently does not.
- Symptom
- A backup run fails with a stale restic lock after a crash or reboot.
- Cause
- A previous job died mid-run and left the repository locked.
- Fix
- Nothing to do manually: the next run detects the orphaned lock and runs restic unlock automatically before proceeding. If runs keep failing, check the live log panel for the underlying error.
Do it in one click with Dockstash
Dockstash runs the exact dump above, restics it off-site, and drill-tests the restore automatically — no script to maintain.
Last updated: July 2026
Frequently asked questions
Why is --single-transaction important?
Without it, mysqldump reads tables one at a time and a write between tables produces an inconsistent dump. --single-transaction wraps everything in one InnoDB transaction so the whole dump reflects a single point in time, with no write lock.
Does the dump include stored procedures and triggers?
Only if you pass --routines and --triggers, which Dockstash includes. A default mysqldump omits them, which is a common cause of a "restored but broken" database.
Can I back up MySQL by copying /var/lib/mysql?
No. The InnoDB tablespace and redo logs are written continuously; a file copy mid-write is inconsistent. Dockstash runs mysqldump inside the container instead.
What if I use MyISAM tables?
--single-transaction does not make MyISAM consistent because it is non-transactional. If you rely on MyISAM, a brief lock (--lock-tables) is required — migrating those tables to InnoDB is the durable fix.
How often should I back up MySQL?
Daily is the practical default for most projects; hourly if losing a day of writes is unacceptable. On the Free tier backups are manual only; Pro allows schedules up to hourly, Business any cron. Pair the schedule with a weekly restore drill so every week you get proof the backup actually restores.
Where do the backups actually live?
On your own storage VPS, as encrypted restic snapshots pushed over SSH. Dockstash never holds your data on a third-party cloud — you point it at a box you control, and the repository is encrypted with a password only you have.
How do I know the backup is restorable without doing a manual restore?
Schedule a restore drill. Dockstash restores the latest snapshot into an isolated scratch workspace, byte-hashes every file against the source, and row-diffs the restored dump — then stamps a pass/fail badge on the project. A weekly drill means you always have fresh proof.