Docs / Databases / MySQL Backup and Recovery Strategies

MySQL Backup and Recovery Strategies

By Admin · Mar 18, 2026 · Updated Apr 23, 2026 · 138 views · 2 min read

Backup Types

Method Speed Size Point-in-Time Lock?
mysqldump Slow Small (compressed) No Brief
mysqlpump Medium Small No Brief
Percona XtraBackup Fast Full size Yes No
Filesystem snapshot Fastest Full size No Brief

mysqldump

Single Database

mysqldump -u root -p mydb > mydb_backup.sql

# Compressed
mysqldump -u root -p mydb | gzip > mydb_$(date +%Y%m%d).sql.gz

All Databases

mysqldump -u root -p --all-databases --single-transaction > all_dbs.sql

Key Flags

mysqldump \
  --single-transaction \     # Consistent snapshot without locking (InnoDB)
  --routines \               # Include stored procedures
  --triggers \               # Include triggers
  --events \                 # Include scheduled events
  --quick \                  # Don't buffer results in memory
  --set-gtid-purged=OFF \    # For non-replication backups
  mydb > backup.sql

Automated Daily Backups

#!/bin/bash
# /opt/backup/mysql-daily.sh

BACKUP_DIR="/backup/mysql"
RETENTION_DAYS=14
DATE=$(date +%Y%m%d_%H%M)

mkdir -p "$BACKUP_DIR"

# Dump all databases
mysqldump --all-databases --single-transaction --routines --triggers \
  | gzip > "${BACKUP_DIR}/all_${DATE}.sql.gz"

# Remove old backups
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +${RETENTION_DAYS} -delete

echo "Backup completed: all_${DATE}.sql.gz ($(du -h ${BACKUP_DIR}/all_${DATE}.sql.gz | cut -f1))"

Restoring

# From plain SQL
mysql -u root -p mydb < mydb_backup.sql

# From compressed
gunzip < mydb_backup.sql.gz | mysql -u root -p mydb

# Restore specific table
mysql -u root -p mydb -e "source /backup/mydb_backup.sql"

Point-in-Time Recovery

Requires binary logging:

# /etc/mysql/mysql.conf.d/mysqld.cnf
log_bin = /var/log/mysql/mysql-bin
expire_logs_days = 14
max_binlog_size = 100M
# Restore to specific point in time
mysqlbinlog --stop-datetime="2026-03-15 14:30:00" /var/log/mysql/mysql-bin.000001 | mysql -u root -p

Verification

Danger A backup you haven't tested is not a backup. Schedule monthly restore tests to a separate server.

# Quick integrity check
gunzip -t backup.sql.gz && echo "File OK"

# Full restore test
mysql -u root -p -e "CREATE DATABASE backup_test;"
gunzip < backup.sql.gz | mysql -u root -p backup_test
mysql -u root -p -e "SELECT COUNT(*) FROM backup_test.users;"
mysql -u root -p -e "DROP DATABASE backup_test;"

Was this article helpful?