This guide provides instructions for creating a complete 1:1 MySQL export that includes all databases, users with passwords, triggers, events, and procedures for testing environments.
- Quick Start - Simple Complete Backup
- What Gets Exported
- Restoration Process
- Verification
- Advanced Options
- Best Practices
- Troubleshooting
For a complete 1:1 copy of your MySQL server, this single command is sufficient:
mysqldump -u root -p \
--all-databases \
--routines \
--triggers \
--events \
--single-transaction \
--master-data=2 \
> full_backup.sqlThat's it! This command creates a complete backup including:
- ✅ All databases
- ✅ All users and their passwords (stored in the
mysqldatabase) - ✅ All privileges and grants
- ✅ All stored procedures and functions
- ✅ All triggers
- ✅ All scheduled events
- ✅ Binary log position (as a comment) for replication or point-in-time recovery
To restore on your test server:
mysql -u root -p < full_backup.sqlThe --all-databases flag exports every database on your server, including:
- All user databases - Your application databases
- The
mysqldatabase - Contains all user accounts, password hashes, and privileges - Other system databases - Like
sys(if present)
Important: The mysql database contains these critical tables:
user- User accounts and password hashesdb- Database-level privilegestables_priv- Table-level privilegescolumns_priv- Column-level privilegesprocs_priv- Procedure/function privilegesproxies_priv- Proxy privileges
| Option | Purpose | Required? |
|---|---|---|
--all-databases |
Exports all databases including mysql (users/passwords) |
Yes |
--routines |
Includes stored procedures and functions | Yes |
--triggers |
Includes all triggers | Yes |
--events |
Includes scheduled events | Yes |
--single-transaction |
Ensures consistent backup for InnoDB tables | Recommended |
--master-data=2 |
Adds binary log position as comment for replication/recovery | Recommended |
The --master-data=2 option adds the binary log filename and position as a comment in your dump file:
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000003', MASTER_LOG_POS=154;Why include it:
- Replication setup - Know exactly where to start replication if you later make this test server a replica
- Point-in-time recovery - Combined with binary logs, restore to any specific moment after the backup
- Documentation - Records the exact binary log position when the backup was taken
- No downside - As a comment, it doesn't affect the restore process
Note: Using --master-data=2 (with =2) adds it as a comment only. Using --master-data=1 would execute the CHANGE MASTER command on restore, which you typically don't want for a test copy.
# 1. Stop applications using the database (optional but recommended)
systemctl stop your-application
# 2. Restore the complete backup
mysql -u root -p < full_backup.sql
# 3. Restart applications
systemctl start your-application# If you compressed your backup
gunzip -c full_backup.sql.gz | mysql -u root -pmysql -u root -p -e "
SELECT
(SELECT COUNT(*) FROM information_schema.SCHEMATA) as 'Databases',
(SELECT COUNT(*) FROM information_schema.TABLES) as 'Tables',
(SELECT COUNT(*) FROM information_schema.ROUTINES) as 'Routines',
(SELECT COUNT(*) FROM information_schema.TRIGGERS) as 'Triggers',
(SELECT COUNT(*) FROM information_schema.EVENTS) as 'Events',
(SELECT COUNT(*) FROM mysql.user) as 'Users';"Run the same query on the restored database and compare the numbers.
# Test that a specific user can still login
mysql -u someuser -p -e "SELECT 'User login successful';"For specific requirements, you might want to add these options:
mysqldump -u root -p \
--all-databases \
--routines \
--triggers \
--events \
--single-transaction \
--master-data=2 \ # Binary log position (recommended)
--flush-privileges \ # Adds FLUSH PRIVILEGES to the dump
--hex-blob \ # Better handling of binary data
--add-drop-database \ # Adds DROP DATABASE before CREATE
--add-drop-table \ # Adds DROP TABLE before CREATE
--order-by-primary \ # Consistent ordering of data
--tz-utc \ # Handles timezones consistently
> full_backup.sqlFor MySQL 8.0 and later, MySQL Shell provides a modern alternative:
# Start MySQL Shell
mysqlsh -u root -p
# In MySQL Shell, run:
util.dumpInstance("/path/to/backup/directory", {
includeUsers: true, # This is default true
includeRoutines: true,
includeEvents: true,
includeTriggers: true,
showProgress: true
})
# To restore:
util.loadDump("/path/to/backup/directory")Advantages of MySQL Shell:
- Parallel processing (faster for large databases)
- Better handling of modern MySQL features
- Progress indication
- More granular control
| Feature/Option | mysqldump | MySQL Shell |
|---|---|---|
| Output Format | Single SQL file | Directory with multiple files |
| Consistent Backup | --single-transaction |
consistent: true |
| Include Triggers | --triggers |
includeTriggers: true |
| Include Routines | --routines |
includeRoutines: true |
| Include Events | --events |
includeEvents: true |
| Binary Log Position | --master-data=2 |
Automatically captured in metadata |
| Compression | Pipe to gzip (| gzip) |
compression: 'gzip' (built-in) |
| Data Format | Text-based SQL statements | Binary/JSON format |
| Restore Speed | Slower (SQL parsing) | Faster (optimized binary) |
| Parallel Processing | Single-threaded | Multi-threaded (threads: N) |
| Progress Indication | No built-in progress | showProgress: true |
| Chunking Large Tables | Not available | Automatic chunking |
| Include Users | --all-databases includes mysql DB |
includeUsers: true (with dumpInstance) |
| Exclude Schemas | --ignore-database=name |
excludeSchemas: ['name1', 'name2'] |
| Character Set | --default-character-set |
defaultCharacterSet: 'utf8mb4' |
| File Size | Larger (SQL text) | Smaller (binary + better compression) |
| Restore Command | mysql -u root -p < dump.sql |
util.loadDump('directory') |
| Version Compatibility | Manual handling | compatibility: ['strip_restricted_grants'] |
| Memory Usage | --quick for low memory |
Automatic optimization |
| Lock Tables | --lock-tables=false |
Handled automatically |
You might need to export users separately in these specific cases:
- Cross-version migrations - When MySQL versions differ significantly
- Selective restoration - When you want data but NOT users
- GTID conflicts - In replication setups with GTID enabled
- System table incompatibilities - Between major MySQL versions
If you need separate user export for these cases:
# Export just users and grants as SQL statements
mysql -u root -p -NBe "
SELECT CONCAT('CREATE USER IF NOT EXISTS \'', user, '\'@\'', host, '\'
IDENTIFIED WITH \'', plugin, '\' AS \'', authentication_string, '\';')
FROM mysql.user
WHERE user NOT IN ('mysql.sys', 'mysql.session', 'mysql.infoschema');" > users.sql
mysql -u root -p -NBe "
SELECT CONCAT('SHOW GRANTS FOR \'', user, '\'@\'', host, '\';')
FROM mysql.user
WHERE user NOT IN ('mysql.sys', 'mysql.session', 'mysql.infoschema');" | \
mysql -u root -p -N | sed 's/$/;/g' > grants.sql# Compress on the fly
mysqldump -u root -p \
--all-databases \
--routines \
--triggers \
--events \
--single-transaction \
--master-data=2 \
| gzip > full_backup.sql.gz
# Restore compressed backup
gunzip -c full_backup.sql.gz | mysql -u root -p#!/bin/bash
# Simple automated backup script
BACKUP_DIR="/backup/mysql"
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/mysql_backup_${DATE}.sql"
# Create backup directory if it doesn't exist
mkdir -p "$BACKUP_DIR"
# Create the backup
mysqldump -u root -p \
--all-databases \
--routines \
--triggers \
--events \
--single-transaction \
--master-data=2 \
> "$BACKUP_FILE"
# Compress it
gzip "$BACKUP_FILE"
echo "Backup completed: ${BACKUP_FILE}.gz"
echo "Size: $(du -h ${BACKUP_FILE}.gz | cut -f1)"
# Optional: Remove backups older than 7 days
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +7 -delete-
Use .my.cnf for passwords instead of command line:
# ~/.my.cnf [client] user=root password=your_password
chmod 600 ~/.my.cnf -
Encrypt sensitive backups:
mysqldump [options] | gzip | gpg --symmetric --cipher-algo AES256 > backup.sql.gz.gpg
-
Restrict file permissions:
chmod 600 full_backup.sql
- Use --single-transaction for InnoDB tables to avoid locking
- Use compression for large databases to save space
- Schedule backups during low-traffic periods
- Consider --quick flag for very large tables (dumps row by row)
- Always test restore on a separate test instance
- Verify backup completeness before relying on it
- Keep multiple backup generations
- Document MySQL versions for compatibility:
mysql --version > mysql_version.txt
Ensure the backup user has sufficient privileges:
GRANT ALL PRIVILEGES ON *.* TO 'backup_user'@'localhost' WITH GRANT OPTION;
GRANT PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'backup_user'@'localhost';
FLUSH PRIVILEGES;Note: The --master-data=2 option requires RELOAD and REPLICATION CLIENT privileges.
mysql -u root -p --max_allowed_packet=1024M < backup.sqlmysqldump --column-statistics=0 [other options]If you encounter GTID-related errors, you may need to reset GTID state:
RESET MASTER;
-- Then restore your backupIf you need specific databases only:
# Specific databases
mysqldump -u root -p --databases db1 db2 db3 --routines --triggers --events --master-data=2 > partial_backup.sql
# Exclude certain databases
mysqldump -u root -p --all-databases \
--ignore-database=test \
--ignore-database=temp \
--routines --triggers --events --master-data=2 > backup_without_test.sqlmysqldump -u root -p --all-databases --routines --triggers --events --single-transaction --master-data=2 > backup.sqlmysql -u root -p < backup.sqlmysqldump -u root -p --all-databases --routines --triggers --events --single-transaction --master-data=2 | gzip > backup.sql.gzgunzip -c backup.sql.gz | mysql -u root -pFor a complete 1:1 MySQL copy for testing:
- Use the simple command - It includes everything you need
- The
--all-databasesflag includes users - No separate user export needed - Include
--master-data=2- Captures binary log position for future flexibility - Test your restore - Always verify on a test instance
- Use compression - For large databases
- Keep it simple - Don't overcomplicate unless you have specific requirements
The beauty of mysqldump --all-databases is that it truly captures everything, making it perfect for creating test environments that exactly mirror production. The addition of --master-data=2 ensures you have the binary log position recorded for potential future use in replication or point-in-time recovery scenarios.
Last updated: 2024
MySQL versions covered: 5.5, 5.6, 5.7, 8.0+