MySQL dump: back up and restore with mysqldump
mysqldump commands that produce a complete, consistent backup, how to restore it, and fixes for the errors that show up in between.
Quick answer
Back up one database:
Restore it into a database that already exists:
That covers most MySQL dump jobs. The flags matter more than they look: without --routines and --events, stored procedures and scheduled events are left out of the file, and the dump still finishes without complaint. Every command in this guide was run against MySQL 8.4 with the mysqldump 8.4 client, and the error text is copied from those runs.
How to dump a MySQL database with mysqldump
mysqldump connects to a running server and writes SQL: CREATE TABLE statements followed by INSERT statements for the rows. Restoring means running that SQL again.
The top of the file looks like this:
Some variations you will use:
--all-databases includes the mysql system schema, which holds user accounts and privileges. Keep that in mind before restoring an all-databases dump onto a server that already has its own users.
The password warning
Passing the password as -psecret works but prints this on every run:
It goes to stderr, so it does not end up in your dump file. For scripts, use -p with no value to get a prompt, set the MYSQL_PWD environment variable, or put the credentials in an option file such as ~/.my.cnf.
--single-transaction: a consistent dump without locking
By default mysqldump runs with --lock-tables, which takes a read lock on the tables of each database while it dumps them. Writes to InnoDB tables wait until the lock is released.
On InnoDB tables, --single-transaction is the better choice. It starts a transaction with a consistent snapshot, reads every table from that snapshot, and turns --lock-tables off. Your application keeps writing, and the dump reflects a single point in time.
The limits, from the mysqldump --help text in 8.4:
So: use it for InnoDB, and do not run migrations while the dump is in progress.
Routines, triggers, and events
These three are handled differently, which is how people end up with incomplete backups.
| Object | Included by default? | Flag |
|---|---|---|
| Triggers | Yes | --skip-triggers to leave them out |
| Stored procedures and functions | No | --routines (-R) |
| Events | No | --events (-E) |
To check, create a trigger, a procedure, and an event in the same database, then dump with and without the flags:
The plain dump has the trigger and nothing else. If your application relies on a stored procedure, a restore from plain.sql will look successful and then fail the first time that procedure is called.
Compressing a MySQL dump with gzip
SQL text compresses well. Pipe through gzip rather than writing an uncompressed file first:
To restore, decompress into mysql:
Or zcat shop.sql.gz | mysql -u root -p shop, which does the same thing on Linux.
Restoring a dump
A single-database dump made without --databases has no CREATE DATABASE or USE statement. It restores into whichever database you name, and that database has to exist:
Create it first:
This is also how you restore under a different name. A dump made with --databases or --all-databases contains its own CREATE DATABASE and USE lines, so it always restores into the original database name:
You can also restore from inside the mysql client with source shop.sql, which prints the result of each statement as it goes.
Work With Your Databases Like A Pro
Query, explore, and manage your databases with a beautiful desktop app and built-in AI.
Download Now
mysqldump with Docker
When MySQL runs in a container, run mysqldump inside it with docker exec and redirect the output on the host:
The password warning goes to stderr, so the file on the host is clean.
Restoring needs -i. Without it, Docker does not forward your shell's stdin into the container, and mysql runs with no input:
Both commands exit with status 0. Only the second one creates any tables, so check the result rather than trusting the exit code.
Common mysqldump errors
Access denied; you need the PROCESS privilege
A user without the global PROCESS privilege gets this:
The dump file is still written and the exit code is 0. mysqldump is trying to read tablespace information, which needs the global PROCESS privilege. Unless you use general tablespaces, add --no-tablespaces:
Access denied when using LOCK TABLES (1044)
The default --lock-tables behaviour needs the LOCK TABLES privilege. For InnoDB tables, add --single-transaction, which turns table locking off and needs no extra privilege. Otherwise grant LOCK TABLES on the database.
Couldn't execute 'show events' (1044)
--events needs the EVENT privilege on the database. Grant it, or drop --events if the database has none.
Stored procedures missing, no error at all
This one prints nothing. A user without the SHOW_ROUTINE privilege (or global SELECT) can run mysqldump --routines, get exit code 0, and produce a file with no procedures in it. In testing, a user with SELECT on the database got zero CREATE PROCEDURE statements. After GRANT SHOW_ROUTINE ON *.* TO 'app'@'%', the procedure appeared. A separate user with global SELECT also got it.
If you back up with a limited user, grep the dump for your routines once to confirm they are there.
Can't connect to local MySQL server through socket (2002)
With no -h, or with -h localhost, the client uses a Unix socket, and there is no server on it. Either the server is not running, or it is somewhere else, such as a Docker container. Pass -h 127.0.0.1 -P 3306 to force TCP, or run mysqldump inside the container as shown above.
Unknown table 'COLUMN_STATISTICS' in information_schema (1109)
Running the MySQL 8.4 mysqldump against a MariaDB server fails with:
MySQL 8's mysqldump has --column-statistics on by default and queries a table that MariaDB does not have. Add --skip-column-statistics, or use MariaDB's own mariadb-dump.
Restore fails on DEFINER: errors 1227 and 1419
Dumps of triggers, procedures, events, and views record who created them:
Restoring that file as a non-root user fails. On a server with binary logging enabled (the default in MySQL 8.4), the first error is usually this one, raised on the trigger:
With log_bin_trust_function_creators turned on, the next error is about the definer itself:
You see these often on managed services, where nobody gets SUPER. The usual fix is to strip the DEFINER clauses so the objects are created as the restoring user:
That removes the 1227 error. The 1419 error still needs log_bin_trust_function_creators = 1 on the target server. With both in place, the restore completes and the trigger's definer becomes the restoring user.
mysqlpump is gone
mysqlpump was deprecated in MySQL 8.0.34 and removed in MySQL 8.4, along with its lz4_decompress and zlib_decompress helpers. The MySQL 8.4 manual points to mysqldump or MySQL Shell's dump utilities instead. Scripts that call mysqlpump will fail on an 8.4 client.
MySQL Shell dump utilities for large databases
mysqldump writes one SQL stream from one thread, and restoring it replays every INSERT in order. On large databases, both ends get slow. MySQL Shell's util.dumpSchemas(), util.dumpInstance(), and util.loadDump() dump with multiple threads (4 by default), write zstd-compressed chunks, and load in parallel.
The output is a directory of metadata files and .tsv.zst data chunks, not a single .sql file, so you restore it with MySQL Shell rather than mysql. loadDump also needs local_infile enabled on the target, and says so if it is not:
For small and medium databases, mysqldump is simpler: one file you can read, grep, edit, and restore with the standard client.
Quick reference
| Task | Command |
|---|---|
| Dump one database | mysqldump -u root -p --single-transaction --routines --events shop > shop.sql |
| Dump schema only | mysqldump -u root -p --no-data shop > schema.sql |
| Restore | mysql -u root -p shop < shop.sql |
| Restore into Docker | docker exec -i container mysql -u root -p... shop < shop.sql |
| Limited user without PROCESS | add --no-tablespaces |
| Dump a MariaDB server with MySQL 8 tools | add --skip-column-statistics |
Related: MySQL CREATE DATABASE for creating the restore target, MySQL CREATE USER for setting up a dedicated backup user, and MySQL list databases to confirm what the restore created.