#

Databases

Subscribe
Databases October 29, 2026·12 min read

How to Back Up and Restore MySQL with mysqldump

Use mysqldump for a manageable MySQL database when a transactional snapshot gives you the consistency you need. Validate every dump by restoring it into a separate test database. If a SQL dump can't meet your consistency or recovery-time needs, choose a physical, parallel, or managed backup instead.

The basic workflow

MySQL backup workflow

A basic MySQL backup has three steps: export the source database to a SQL file, load that file into an empty database on a test server, and check the result. A dump is not a recovery proof until it imports into an isolated database and you can inspect the expected tables there.

The examples use a Linux shell, MySQL 8.4 command behavior, and example database names. Run the export on the source server. Run the import from a machine that can reach a separate test MySQL instance.

  • example_app: The source database.
  • example_app.sql: The SQL backup file.
  • example_app_restore: A new, empty database on the test instance.
  • TEST_HOST: The test server's hostname or address. Replace it with the real one.
  • backup_user and restore_user: Accounts with the permissions each operation needs.

Export the source database:

mysqldump -u backup_user -p example_app > example_app.sql

The -p option prompts for a password. Shell redirection writes the generated SQL to example_app.sql.

Once the empty destination database exists on the test instance, import the file:

mysql --host=TEST_HOST -u restore_user -p \
  example_app_restore < example_app.sql

The mysql client runs the saved SQL on the server named by --host. The SQL file must be reachable from the machine running this command.

This example dumps one database without --databases, so the file has no CREATE DATABASE or USE statements and the destination database must already exist.

Keep the target separate: TEST_HOST must point to the test instance. Without an explicit host or another known connection configuration, the MySQL client connects to localhost. Don't assume a different database name isolates you from the production server.

When mysqldump fits the recovery goal

MySQL backup choices

mysqldump suits a manageable logical export, such as copying an application database into a development environment, because the SQL output is portable and readable. Physical backups preserve the underlying database files and can be the better choice when a large database must come back within a short downtime window. MySQL Shell supports parallel dumping, loading, and compression.

Pick by three things: how much data you can afford to lose, how long you can stay down, and how consistent the data must be.

Check your database before the dump

MySQL database inspection

On the Linux machine where the client tools run, check the installed versions:

mysql --version
mysqldump --version

The storage-engine information in information_schema.tables separates InnoDB from nontransactional engines such as MyISAM and MEMORY.

Also find out whether the application relies on views, triggers, stored procedures, functions, or scheduled events.

Database object inventory

Write down five things:

  • Source identity: Server, database name, and server and client versions.
  • Engine mix: InnoDB tables, plus any nontransactional tables that change the consistency strategy.
  • Object list: Views, triggers, routines, and events the application needs.
  • Access: The export permissions the backup account actually has.
  • Destination: The separate test instance and the name reserved for the restored database.

For MySQL 8.4, table exports require SELECT, views require SHOW VIEW, triggers require TRIGGER, and events require EVENT. Routine dumping and some options need more access.

One combination matters: --single-transaction with gtid_mode=ON and --set-gtid-purged=ON or AUTO. MySQL documents a requirement for the RELOAD or FLUSH_TABLES privilege under those conditions. Check your own options instead of copying a generic list of grants.

Choose the dump scope

MySQL dump scope

Scope decides what goes into the file and how the file picks databases at import.

Required scopeExample commandImport consequence
One databasemysqldump -u backup_user -p example_app > example_app.sqlRestores into any existing database you name
Selected tablesmysqldump -u backup_user -p example_app table1 table2 > selected_tables.sqlRestores only the named tables
Multiple databasesmysqldump -u backup_user -p --databases app_a app_b > selected_databases.sqlIncludes CREATE DATABASE and USE statements
All databasesmysqldump -u backup_user -p --all-databases > all_databases.sqlSame, for every database

--all-databases exports the whole instance, but not every internal schema. MySQL excludes INFORMATION_SCHEMA, and performance_schema and sys are not dumped by default.

SQL export statements

Two more options cover narrower jobs:

  • --no-data: Exports object definitions without the table rows.
  • --no-create-info: Exports table data without the usual table-creation statements.

For a normal application recovery, use a scope that includes both structure and data.

Use --single-transaction correctly for live InnoDB data

InnoDB transactional snapshot

For a live InnoDB database, --single-transaction lets mysqldump read a consistent snapshot while normal application writes continue.

In MySQL 8.4, the option starts a transaction under repeatable-read isolation. InnoDB then supplies a view of the data committed as of the transaction's start.

For example_app, assuming InnoDB tables and no concurrent schema changes affecting them, use:

mysqldump -u backup_user -p \
  --single-transaction --quick \
  example_app > example_app.sql

--quick retrieves rows incrementally, which helps with large tables. The default --opt option group already enables it.

The snapshot guarantee covers transactional engines such as InnoDB. MyISAM and MEMORY tables don't get it. Concurrent ALTER TABLE, CREATE TABLE, DROP TABLE, RENAME TABLE, or TRUNCATE TABLE operations on affected tables can also compromise the dump. --single-transaction and --lock-tables are mutually exclusive.

Online dump constraints

A Docker operator on r/selfhosted described a related concern: “I've been noticing some tar corruptions, and I'm reading a lot about how you shouldn't backup running DBs but dump them.”

A logical export and a filesystem archive of active database files use different consistency mechanisms. On a mixed-engine deployment, your engine list and schema-change activity decide whether the transactional export is enough.

The MySQL mysqldump reference documents the engine and concurrent-DDL restrictions.

Back up stored objects

MySQL stored objects

MySQL can keep application behavior in views, triggers, routines, and scheduled events, and each has its own export rules.

In MySQL 8.4, triggers are included by default when the exporting account has the required permissions.

ObjectWhat the dump needs
Tables and rowsChosen by the database and table scope
ViewsSHOW VIEW access. Definitions must be compatible with the target
TriggersIncluded by default. Needs TRIGGER
Procedures and functions--routines
Scheduled events--events plus EVENT access

The explicit routine and event options matter even with --all-databases in MySQL 8.4, because those definitions live in the data dictionary.

For an InnoDB application that needs its stored programs and events, run:

mysqldump -u backup_user -p \
  --single-transaction --quick \
  --routines --events --triggers \
  example_app > example_app.sql

In MySQL 8.4, --routines requires the global SELECT privilege. Table-level SELECT alone doesn't satisfy it.

Stored program backup

Views, routines, and events can carry definitions or DEFINER values that need compatible permissions on the destination.

MySQL configuration, server logs, application files, and database-account provisioning sit outside the dump and need separate treatment. A full WordPress recovery, for example, needs the site's files as well as its database.

Compress and automate dumps without hiding failures

Compressed MySQL backup

Compression cuts the space a SQL dump needs for storage and transfer. A compressed file can still exist when mysqldump failed.

mysqldump example_app | gzip > example_app.sql.gz

By default, a Bash pipeline returns the exit status of its last command. If mysqldump fails and gzip finishes successfully, a script that checks the default status misses the export failure.

For a controlled Bash job, turn on pipeline failure detection:

#!/usr/bin/env bash
set -euo pipefail

mysqldump --single-transaction --quick \
  example_app | gzip > example_app.sql.gz

gzip -t example_app.sql.gz

The script assumes a protected MySQL client authentication configuration, and its transactional options assume InnoDB tables and no concurrent DDL. It is not a complete unattended backup service.

pipefail passes on a nonzero status from any failing pipeline component, and with set -e that stops the script. gzip -t then checks the integrity of the compressed stream. You evaluate the recovered database after import.

Bash backup validation

A file on disk doesn't prove the export worked. Check the exit status and error output before counting it as a backup.

In Bash, > truncates an existing file before the export runs. Give each new attempt a distinct filename or a temporary path, and keep the last validated backup until its replacement passes the checks. A name like example_app-YYYYMMDD.sql.gz works, with the job filling in the date.

Keep passwords out of command arguments. Use interactive -p or a protected client configuration. The MySQL connection options documentation covers authentication handling.

pipefail works in Bash and shells with comparable behavior.

Restore a SQL dump without overwriting the wrong database

MySQL restore destination

Before you restore, decide which server gets the file and check which databases the file selects.

For the plain single-database example, create a new, empty example_app_restore database on the separate test MySQL instance. The account needs permission to create it:

mysql --host=TEST_HOST -u restore_user -p \
  -e "CREATE DATABASE example_app_restore;"

Then import the uncompressed file with the mysql --host=TEST_HOST command from the basic workflow.

For a compressed file, use a Bash pipeline that propagates failures:

set -o pipefail
gzip -dc example_app.sql.gz | \
  mysql --host=TEST_HOST -u restore_user -p example_app_restore

Check the pipeline's exit status and the import's error output. The receiving database should start empty.

A dump made with --databases or --all-databases brings its own CREATE DATABASE, USE, and object-replacement statements.

SQL restore isolation

On r/mysql, a poster asked: “How can I restore 1 db name "test" in "test_uat" from all database file in same windows MySQL server?”

The name you choose at restore time doesn't change the names inside the SQL. MySQL's --one-database client option follows the default database selected by USE. It doesn't inspect every statement to find all the schemas that statement modifies.

The MySQL client command options reference explains why an explicitly qualified cross-schema statement can still run under a matching USE context.

Before importing, search the dump for CREATE DATABASE, USE, DROP TABLE, DROP DATABASE, and qualified references to other schemas. If you want only one database from that dump under a new name, restore everything on an isolated instance, then export that one database again.

Test the restored database

MySQL recovery verification

A backup is useful only if its SQL imports and the restored database has the structure, data, and behavior you need.

One operator on r/selfhosted asked: “How do you test your backups to make sure they actually work?”

Run the check against the isolated destination and compare it with the object list you wrote before the dump.

Restore checkWhat to look at
SQL importClient exit status and import errors
Database objectsExpected tables, views, triggers, routines, and events
Representative dataKnown non-sensitive records or application queries
Application behaviorAn important operation in staging, if an application uses the database
Restore durationElapsed time, if you measure it

Start with an object check against example_app_restore on the test instance:

mysql --host=TEST_HOST -u restore_user -p \
  -e "SHOW TABLES FROM example_app_restore;"

For a real table from your source list, a representative row-count query looks like this:

mysql --host=TEST_HOST -u restore_user -p \
  -e "SELECT COUNT(*) FROM example_app_restore.example_table;"

example_table is a placeholder. Replace it with a real table name and compare the result with the value you expect.

Restore acceptance checks

A table list and a row count can't confirm complete application recovery. Also check any required stored programs, and run a relevant operation in a disposable staging application if one uses the database.

Record the test date, source and destination versions, the exact backup file, any failures or exceptions, and the restore time if you measured it. A passing test shows the checked backup can be recovered in that environment.

Fix mysqldump and MySQL restore failures by symptom

MySQL failure diagnosis

First decide which stage failed: authentication, connection, export, compression, or SQL import.

SymptomLikely stageWhat to do
Access denied during exportAuthentication or object privilegeCheck which privilege the failing object needs and grant it
PROCESS privilege errorTablespace-related exportIf you don't need tablespace SQL, use --no-tablespaces
Cannot connectClient connectionCheck host or socket, service state, and credentials, then fix the one that fails
Missing or incomplete fileExport or compressionCheck exit status, errors, and output storage, fix the failing stage, and create a new file
Existing table or unknown databaseSQL importCompare the dump statements with the destination state, then import into a clean test target
DEFINER or SQL compatibility errorSQL importRead the failing statement and compare the target's privileges and product versions against it

MySQL 8.4 supports --no-tablespaces to omit tablespace DDL. That removes the PROCESS privilege requirement when you don't need the metadata, but it changes what the dump contains.

Interrupted SQL restore

A user on r/mysql asked: “Can I again start backup/restoration in mysql from that point where it was failed.”

An interrupted export can leave a partial file, and a failed import can already have changed the destination. Appending to the dump or rerunning the SQL over an altered database gives you no safe resume point.

Find the failed operation, fix its cause, then create a fresh backup or restart the import into a clean test target. Broad administrator grants, forced imports, and automatic database deletion make poor fixes.

Account for MariaDB differences and MySQL GTID state

Database client compatibility

A dump that crosses between MariaDB and MySQL client or server families needs version-aware handling. MariaDB documents mariadb-dump as its dump utility.

In the MariaDB 11 official Docker image, the mysqldump compatibility name is absent. The MariaDB dump format can also contain a sandbox-mode command that older MariaDB clients or the MySQL mysql client can't interpret.

GTIDs are a separate issue for replication-sensitive MySQL exports and imports. With GTIDs enabled, the default --set-gtid-purged=AUTO can add GTID-related and session binary-logging statements to the dump.

For a partial dump, the GTID information can reflect transactions beyond the exported databases. Choose OFF or COMMENTED to match the target's replication and recovery requirements.

Before a replication-sensitive import, check both product versions and the destination's GTID setup. The MariaDB dump utility reference documents the client-family and sandbox-mode distinctions.

Keep the backup usable

Database backup maintenance

Dump files can contain confidential production data. Restrict access to them and protect every stored and offsite copy.

MySQL recovery planning

Retest after major schema or object changes, server or client upgrades, substantial growth, or a tighter recovery objective.

Point-in-time recovery needs a base backup plus the binary-log events that replay later changes. A SQL file created earlier can't reconstruct later transactions by itself.

NoScript Team