Get started

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.

Detection

What Dockstash detects

Env keys detectedMYSQL_ROOT_PASSWORD, MYSQL_DATABASE, MYSQL_USER, MYSQL_PASSWORD
Default port3306
Live data paths (never copied live)/var/lib/mysql
Example imagesmysql:8, mysql:8.0, mysql:5.7, mysql
Step by step

Back up MySQL with Dockstash, step by step

  1. 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.

  2. 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.

  3. 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.

  4. 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 20
  5. Confirm 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.

  6. 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.

  7. 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.

  8. 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.

Commands

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 & verify

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.

  1. 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.

  2. 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.

  3. 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;"'
  4. 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.

The gotchas

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.
Troubleshooting

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.