Databases 57 min read

Master MySQL Automatic Backup and Recovery: Full Step‑by‑Step Guide

This comprehensive tutorial walks Linux and DevOps engineers through MySQL backup fundamentals, logical and physical backup tools (mysqldump, XtraBackup), binlog‑based point‑in‑time recovery, automated scripting, monitoring, risk mitigation, common pitfalls, and best‑practice recommendations for building a reliable backup‑restore system.

MaGe Linux Operations
MaGe Linux Operations
MaGe Linux Operations
Master MySQL Automatic Backup and Recovery: Full Step‑by‑Step Guide

Background and Applicable Scenarios

MySQL is a core component for most business systems. Accidental operations, upgrades, hardware failures, or ransomware can corrupt data. Without backups, recovery requires rebuilding from scratch, which is unacceptable for business continuity. This guide targets Linux operators, DevOps engineers, and junior to mid‑level DBAs, covering a complete automatic backup and recovery framework.

Principles of full and incremental backups

Using mysqldump and Percona XtraBackup

Binlog‑based point‑in‑time recovery (PITR)

Backup strategy automation and monitoring

Risk control, performance impact, and troubleshooting

It is recommended to test the entire process in a non‑production environment before applying it to production.

Backup Types and Core Concepts

Logical vs Physical Backup

Logical backup (e.g., mysqldump, mydumper) exports data as INSERT statements or CSV. It is version‑compatible, allows selective table recovery, and produces human‑readable files, but is slower, larger, and may lock tables depending on the storage engine.

Physical backup (e.g., MySQL XtraBackup, mysqlbackup) copies the raw data files ( .frm, .ibd, .ibdata, redo logs). It is faster, preserves page‑level consistency, and is ideal for large databases, but has poor cross‑platform compatibility and restores whole instances only.

Rule of thumb: mysqldump for databases under a few hundred GB; XtraBackup for TB‑scale workloads.

Full vs Incremental Backup

Full backup copies the entire dataset each time. It is simple to restore but consumes more storage and takes longer.

Incremental backup copies only pages changed since the last backup, using the binary log (binlog) and XtraBackup's incremental capability. It is faster and smaller, but restoration requires applying the base full backup followed by each incremental in order.

Common strategy: "full + binlog" – a daily full backup plus binlog snapshots every 15‑30 minutes, enabling recovery to any point in time.

Backup Frequency and Retention

Frequency depends on Recovery Point Objective (RPO) and operational maturity. For a 15‑minute RPO, back up binlog every 15 minutes; for a daily RPO, a daily full backup suffices.

Retention: keep at least 7 days of backups; critical systems may retain 30 days or more. Longer retention increases storage cost but protects against longer‑term logical errors.

mysqldump Practical Guide

mysqldump

is bundled with MySQL and works for most small‑to‑medium workloads.

Basic Usage

mysqldump -u root -p --single-transaction --routines --triggers --events \
  --master-data=2 --flush-logs dbname > /backup/dbname_$(date +%Y%m%d).sql

Key options: --single-transaction: starts a consistent InnoDB transaction, avoiding read locks. --routines, --triggers, --events: include stored procedures, triggers, and events. --master-data=2: records binlog file and position as a comment for later PITR. --flush-logs: rotates binlog before dumping, ensuring the dump’s start point is known.

Compression example:

mysqldump -u root -p --single-transaction --routines --triggers --events \
  --master-data=2 --flush-logs dbname | gzip > /backup/dbname_$(date +%Y%m%d).sql.gz

Dumping a Single Database

mysqldump -u root -p \
  --single-transaction \
  --routines \
  --triggers \
  --events \
  --master-data=2 \
  --flush-logs \
  --databases app_db | gzip > /backup/app_db_$(date +%Y%m%d).sql.gz

Dumping All Databases

mysqldump -u root -p \
  --single-transaction \
  --routines \
  --triggers \
  --events \
  --master-data=2 \
  --flush-logs \
  --all-databases | gzip > /backup/all_db_$(date +%Y%m%d).sql.gz

Dumping a Single Table

mysqldump -u root -p --single-transaction dbname orders users products \
  > /backup/dbname_tables_$(date +%Y%m%d).sql

Useful for recovering a mistakenly dropped table.

Schema‑Only Dump

mysqldump -u root -p --single-transaction --no-data dbname > /backup/dbname_structure_$(date +%Y%m%d).sql

Conversely, use --no-create-info to dump data only.

Large‑Scale Parallel Dump with mydumper

# Install mydumper (CentOS/RHEL)
 yum install -y mydumper
# Install mydumper (Debian/Ubuntu)
 apt-get install -y mydumper
# Parallel export with 4 threads
 mydumper \
   --host=127.0.0.1 \
   --port=3306 \
   --user=root \
   --password='your_password' \
   --threads=4 \
   --outputdir=/backup/export \
   --database=app_db \
   --compress \
   --verbose=3

The output consists of multiple chunk files; restore with myloader.

mysqldump Limitations and Caveats

--single-transaction

works only with InnoDB; MyISAM tables are still locked.

Logical backups of very large databases become slow and produce huge SQL files; use XtraBackup instead.

Backup files are stored in plain text; encrypt them if they contain sensitive data.

Avoid passing passwords on the command line ( -ppassword) because they appear in ps output. Store credentials in /root/.my.cnf with chmod 600.

MySQL XtraBackup Practical Guide (Hot Backup Tool)

Installation

# CentOS/RHEL 7 and earlier
 yum install -y https://repo.percona.com/yum/percona-release-latest.noarch.rpm
 yum install -y percona-xtrabackup-24
# CentOS/RHEL 8 / AlmaLinux 8 / Rocky Linux 8
 dnf install -y https://repo.percona.com/yum/percona-release-latest.noarch.rpm
 dnf install -y percona-xtrabackup
# Debian/Ubuntu
 wget https://repo.percona.com/apt/pool/main/p/percona-release/percona-release_latest.generic_all.deb
 dpkg -i percona-release_latest.generic_all.deb
 apt-get update
 apt-get install -y percona-xtrabackup

Verify installation: xtrabackup --version The examples use XtraBackup 2.4, compatible with MySQL 5.6, 5.7, and 8.0 (some 8.0 features need XtraBackup 8.0).

Full Hot Backup

The process has two steps:

Copy data files:

xtrabackup --backup --target-dir=/backup/xtrabackup/full/$(date +%Y%m%d)

Prepare the backup (apply logs to make it consistent):

xtrabackup --prepare --target-dir=/backup/xtrabackup/full/$(date +%Y%m%d)

Create a minimal‑privilege backup user:

CREATE USER 'backup'@'localhost' IDENTIFIED BY 'Str0ngP@ssword';
GRANT PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'backup'@'localhost';
FLUSH PRIVILEGES;

Run the backup with parallelism and compression:

xtrabackup \
  --backup \
  --user=backup \
  --password='Str0ngP@ssword' \
  --target-dir=/backup/xtrabackup/full/$(date +%Y%m%d) \
  --parallel=4 \
  --compress \
  --compress-threads=4

Key options: --parallel=4: use four threads for copying. --compress: compresses data with qpress (≈2‑3× reduction).

Incremental Backup

First, take a full backup as the base. Then, for each incremental:

# First full backup (base)
FULL_DATE=$(date +%Y%m%d)
 xtrabackup --backup --user=backup --password='Str0ngP@ssword' \
   --target-dir=/backup/xtrabackup/full/${FULL_DATE} \
   --parallel=4
# Record LSN for later use
 cat /backup/xtrabackup/full/${FULL_DATE}/xtrabackup_checkpoints
# Incremental backup after 1 day
INC_DATE=$(date +%Y%m%d)
 xtrabackup --backup --user=backup --password='Str0ngP@ssword' \
   --target-dir=/backup/xtrabackup/incremental/${INC_DATE} \
   --incremental-basedir=/backup/xtrabackup/full/${FULL_DATE} \
   --parallel=4

Typical xtrabackup_checkpoints output:

backup_type = full-backuped
from_lsn = 0
to_lsn = 12345678

Apply multiple increments sequentially:

# Apply only log (no rollback) after full backup
xtrabackup --prepare --apply-log-only --target-dir=/backup/xtrabackup/full/${FULL_DATE}
# Apply first incremental
xtrabackup --prepare --apply-log-only --target-dir=/backup/xtrabackup/full/${FULL_DATE} \
   --incremental-dir=/backup/xtrabackup/incremental/${INC_DATE}
# Apply second incremental (if any)
... (repeat)
# Final prepare without --apply-log-only to make data consistent
xtrabackup --prepare --target-dir=/backup/xtrabackup/full/${FULL_DATE}

Streaming Backup to Remote Host

xtrabackup --backup --user=backup --password='Str0ngP@ssword' \
  --target-dir=/backup/xtrabackup/full/$(date +%Y%m%d) \
  --stream=xbstream --compress \
  | ssh backup@remote-server "cat > /remote/backup/$(date +%Y%m%d).xbstream"
# On remote host, extract and prepare
ssh remote-server "xbstream -x -C /remote/backup/restore < /remote/backup/$(date +%Y%m%d).xbstream"
 xtrabackup --decompress --target-dir=/remote/backup/restore
 xtrabackup --prepare --target-dir=/remote/backup/restore"

When to Use XtraBackup

Data > 100 GB where mysqldump is too slow.

Zero‑downtime backups for 24/7 services.

Need for incremental backups to save storage.

Fast initialization of replica servers.

Not suitable for small databases (< 100 GB), single‑table logical backups, or cross‑version restores.

Binlog Backup: Key to Point‑in‑Time Recovery

Binary logs record every data‑changing statement (INSERT, UPDATE, DELETE, DDL). They are essential for replication and PITR.

Basic Binlog Configuration

[mysqld]
server-id = 1
log_bin = /var/lib/mysql/mysql-bin
binlog_format = ROW
expire_logs_days = 7
max_binlog_size = 1G
sync_binlog = 1

Explanation: log_bin: enables binlog with file prefix. binlog_format = ROW: records row changes (most consistent, larger size). expire_logs_days = 7: keep logs for at least a week. sync_binlog = 1: flushes binlog on every transaction (highest safety, some performance cost).

Manual Binlog Backup

# Create backup directory
mkdir -p /backup/binlog
# Flush logs to rotate current file
mysql -u root -p -e "FLUSH BINARY LOGS;"
# Identify current active binlog
CURRENT_BINLOG=$(mysql -u root -p -N -e "SHOW BINARY LOGS;" | tail -n 1 | awk '{print $1}')
# Copy all completed binlog files (skip the active one)
for file in /var/lib/mysql/mysql-bin.*; do
  fname=$(basename "$file")
  if [[ "$fname" != "$CURRENT_BINLOG" ]]; then
    cp "$file" /backup/binlog/
    echo "Backed up: $fname"
  fi
done

Automation script (cron‑friendly) is provided later.

PITR Process

Restore the latest full backup to a consistent state.

Locate the binlog position recorded in the dump (via --master-data comment).

Replay binlog events from that position up to the desired timestamp using mysqlbinlog.

mysqlbinlog \
  --start-position=12345 \
  --stop-datetime="2024-01-15 14:30:00" \
  /var/lib/mysql/mysql-bin.000014 \
  /var/lib/mysql/mysql-bin.000015 \
  | mysql -u root -p target_db

Use --verbose (or -v) with ROW format to get readable SQL.

Full Backup‑Recovery Workflow: Scenario‑Based Practice

Scenario 1 – Whole Database Drop (mysqldump backup)

Fault: At 02:00 AM, DROP DATABASE app_db; was executed. Need to restore to the state before the drop.

Steps:

Assess loss and locate the latest full backup (e.g., /backup/app_db_20240114.sql.gz from Jan 14 03:00).

Identify the exact timestamp of the DROP using binlog:

mysqlbinlog -v /var/lib/mysql/mysql-bin.000015 | grep -i "DROP DATABASE" -A 5 -B 5

Assume the DROP occurred at 2024-01-15 02:00:32, position 876543.

Re‑create the database (if missing) and restore the full dump:

mysql -u root -p -e "CREATE DATABASE app_db;"
 gunzip < /backup/app_db_20240114.sql.gz | mysql -u root -p app_db

Apply binlog up to one second before the DROP to bring data forward:

mysqlbinlog \
  --start-position=12345 \
  --stop-datetime="2024-01-15 02:00:31" \
  /var/lib/mysql/mysql-bin.000014 \
  /var/lib/mysql/mysql-bin.000015 \
  | mysql -u root -p app_db

Note the use of --stop-datetime to exclude the DROP.

Validate tables, row counts, and recent data.

Risks:

Restoring overwrites current data; test on a replica first.

Binlog replay may hit duplicate‑key errors; use --skip-slave-start or adjust filters.

Always take an immediate backup of the current (possibly corrupted) state before recovery.

Scenario 2 – Single Table Truncate (XtraBackup + binlog)

Fault: TRUNCATE TABLE orders; cleared ~5 M rows.

Steps:

Find the binlog entry for the TRUNCATE (e.g., 2024-01-15 14:22:15, position 54321).

mysqlbinlog -v /var/lib/mysql/mysql-bin.000016 | grep -i "TRUNCATE"

Restore the latest full XtraBackup to a temporary MySQL instance (different port) to extract the pre‑truncate orders table:

# Prepare backup directory
mkdir -p /tmp/mysql_restore
xtrabackup --copy-back --target-dir=/backup/xtrabackup/full/20240114 --datadir=/tmp/mysql_restore
# Start temporary server
mysqld --defaults-file=/etc/my.cnf --port=3307 --socket=/tmp/mysql.sock \
  --datadir=/tmp/mysql_restore --user=mysql &

Export the orders table from the temporary instance:

mysqldump -u root -p -P 3307 app_db orders > /tmp/orders_recover.sql

In production, truncate the (now empty) orders table and import the recovered data:

mysql -u root -p -e "USE app_db; TRUNCATE TABLE orders;"
 mysql -u root -p app_db < /tmp/orders_recover.sql

Verify row counts and timestamps.

Risks:

Running a temporary instance consumes resources; avoid during peak load.

ROW‑format binlog records TRUNCATE as a series of row deletions; ensure the replay captures all rows.

Version mismatches between backup and production MySQL may cause incompatibilities.

Scenario 3 – Full Physical Restore After Disk Failure

Fault: The server’s disk failed, corrupting the data directory.

Steps:

Verify backup set integrity (check xtrabackup_checkpoints for backup_type = full-backuped).

Stop MySQL service ( systemctl stop mysqld).

Back up any residual data (if readable) for forensic purposes.

Clear the data directory ( rm -rf /var/lib/mysql/*).

Copy the backup files back:

xtrabackup --copy-back --target-dir=/backup/xtrabackup/full/20240114

Set correct ownership ( chown -R mysql:mysql /var/lib/mysql).

Start MySQL and verify databases and tables.

If replication is configured, check replica status fields ( Slave_IO_Running, Slave_SQL_Running, Seconds_Behind_Master).

Key points: ensure the backup is complete, permissions are correct, and replication catches up after the restore.

Backup Automation

Backup Script Design Principles

Idempotence : repeated runs do not interfere with ongoing backups.

Logging : record start/end time, file size, success status.

Error handling : send alerts on failure.

Dry‑run mode : validate logic without actual backup.

Retention : automatically purge old backups.

Full mysqldump Backup Script (bash)

#!/bin/bash
# /opt/scripts/mysql_backup.sh
set -euo pipefail

# Configuration
BACKUP_ROOT="/backup/mysql"
MYSQL_HOST="127.0.0.1"
MYSQL_PORT="3306"
MYSQL_USER="root"
MYSQL_PASS="Str0ngP@ssword"
DBS_TO_BACKUP="app_db cache_db log_db"
RETENTION_DAYS=7
LOG_FILE="/var/log/mysql_backup.log"
DRY_RUN=false

log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"; }

die() { log "ERROR: $*"; echo "[ALERT] MySQL backup failed: $*"; exit 1; }

# Verify MySQL connectivity
log "Checking MySQL connection..."
mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" -p"$MYSQL_PASS" -e "SELECT 1;" >/dev/null || die "Cannot connect to MySQL"

# Check free space (need at least 20 GB)
AVAIL=$(df -BG "$BACKUP_ROOT" | awk 'NR==2 {print $4}' | tr -d 'G')
[[ $AVAIL -lt 20 ]] && die "Insufficient disk space: ${AVAIL}GB free"

log "========== Starting MySQL backup =========="
TODAY=$(date +%Y%m%d)
BACKUP_DIR="$BACKUP_ROOT/$TODAY"
mkdir -p "$BACKUP_DIR"

for db in $DBS_TO_BACKUP; do
  log "Backing up database: $db"
  BACKUP_FILE="$BACKUP_DIR/${db}_${TODAY}.sql.gz"
  if [[ "$DRY_RUN" == true ]]; then
    log "[DRY‑RUN] mysqldump -h $MYSQL_HOST -P $MYSQL_PORT -u $MYSQL_USER $db | gzip > $BACKUP_FILE"
    continue
  fi
  mysqldump -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" -p"$MYSQL_PASS" \
    --single-transaction --routines --triggers --events \
    --master-data=2 --flush-logs --databases "$db" | gzip > "${BACKUP_FILE}.tmp" \
    || die "Backup of $db failed"
  mv "${BACKUP_FILE}.tmp" "$BACKUP_FILE"
  SIZE=$(du -h "$BACKUP_FILE" | cut -f1)
  log " -> Saved: $BACKUP_FILE ($SIZE)"
 done

# Binlog backup
log "Backing up binlog..."
BINLOG_DIR="$BACKUP_ROOT/binlog/$TODAY"
mkdir -p "$BINLOG_DIR"
if [[ "$DRY_RUN" == true ]]; then
  log "[DRY‑RUN] Copy binlog files to $BINLOG_DIR"
else
  CURRENT_BINLOG=$(mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" -p"$MYSQL_PASS" -N -e "SHOW BINARY LOGS;" | tail -n 1 | awk '{print $1}')
  mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" -p"$MYSQL_PASS" -e "FLUSH BINARY LOGS;"
  for f in /var/lib/mysql/mysql-bin.*; do
    fname=$(basename "$f")
    if [[ "$fname" != "$CURRENT_BINLOG" ]]; then
      cp "$f" "$BINLOG_DIR/"
    fi
  done
  log " -> Binlog files saved to $BINLOG_DIR"
fi

# Purge old backups
log "Purging backups older than $RETENTION_DAYS days..."
if [[ "$DRY_RUN" == true ]]; then
  log "[DRY‑RUN] find $BACKUP_ROOT -type f -mtime +$RETENTION_DAYS"
else
  find "$BACKUP_ROOT" -type f -mtime +$RETENTION_DAYS -delete
  log "Purge completed"
fi

log "========== Backup completed: $(date '+%Y-%m-%d %H:%M:%S') =========="

Make the script executable:

chmod +x /opt/scripts/mysql_backup.sh

Scheduling with Cron

# Daily full backup at 03:00
0 3 * * * /bin/bash /opt/scripts/mysql_backup.sh >> /var/log/mysql_backup.log 2>&1
# Weekly full backup (all databases) at 04:00 on Sundays
0 4 * * 0 /bin/bash /opt/scripts/mysql_backup.sh >> /var/log/mysql_backup.log 2>&1

Backup Monitoring Script

#!/bin/bash
# /opt/scripts/check_backup.sh
BACKUP_ROOT="/backup/mysql"
ALERT_THRESHOLD_MB=10
RECENT_BACKUP=$(find "$BACKUP_ROOT" -name "*.sql.gz" -type f | sort -r | head -n 1)

if [[ -z "$RECENT_BACKUP" ]]; then
  echo "[ALERT] No backup files found!"
  exit 1
fi

SIZE_MB=$(du -m "$RECENT_BACKUP" | cut -f1)
if [[ $SIZE_MB -lt $ALERT_THRESHOLD_MB ]]; then
  echo "[ALERT] Backup file too small: $RECENT_BACKUP ($SIZE_MB MB)"
  exit 1
fi

BACKUP_DATE=$(stat -c %y "$RECENT_BACKUP" | cut -d' ' -f1)
TODAY=$(date +%Y-%m-%d)
if [[ "$BACKUP_DATE" != "$TODAY" ]]; then
  echo "[ALERT] Latest backup is not from today: $BACKUP_DATE"
  exit 1
fi

echo "[OK] Backup OK: $RECENT_BACKUP ($SIZE_MB MB)"

Integrate this script with Prometheus Alertmanager or any alerting system; a non‑zero exit code triggers an alert.

Parallel mysqldump for Large Environments

# Export function
backup_one_db() {
  local db=$1
  local backup_root=$2
  local today=$(date +%Y%m%d)
  mysqldump -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" -p"$MYSQL_PASS" \
    --single-transaction --routines --triggers --events \
    --master-data=2 --flush-logs --databases "$db" \
    | gzip > "${backup_root}/${db}_${today}.sql.gz"
}
export -f backup_one_db
export BACKUP_ROOT="/backup/mysql"
export MYSQL_HOST MYSQL_PORT MYSQL_USER MYSQL_PASS

echo "app_db cache_db log_db analytics_db" | tr ' ' '
' | \
  parallel -j 4 backup_one_db {} "$BACKUP_ROOT"

Backup Compression and Throttling for XtraBackup

# Limit I/O to reduce impact on production
xtrabackup \
  --backup \
  --user=backup \
  --password='Str0ngP@ssword' \
  --target-dir=/backup/xtrabackup/full/$(date +%Y%m%d) \
  --throttle=100 \
  --parallel=2
--throttle=100

caps I/O operations to 100 per second; adjust based on performance testing.

Risk Control

Testability of Backup & Restore

Monthly : full restore in an isolated environment.

Quarterly : simulate disaster scenarios (single‑table restore, PITR, cross‑server restore).

After any script change : immediate test.

RPO & RTO Assessment

Define acceptable data loss (RPO) and recovery time (RTO). Example matrix:

Core transaction systems: RPO < 5 min, RTO < 30 min → real‑time binlog + hourly full backup.

Standard business apps: RPO 1 hour, RTO 2 hours → 15‑min binlog + daily full.

Internal tools: RPO 24 hours, RTO 24 hours → daily full only.

Backup Data Security

Encrypt backups with GPG or similar; avoid hard‑coding passwords.

Set directory permissions to 700 and files to 600 (owner root/mysql).

Store copies in off‑site object storage (S3, OSS, COS) or remote servers via ssh / rsync.

Use a minimal‑privilege backup user (PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT).

Performance Impact

mysqldump --single-transaction

avoids table locks but still holds an InnoDB snapshot; keep backup windows short.

XtraBackup reads data pages directly; use --throttle and limit parallelism to reduce I/O pressure.

Common Issues & Troubleshooting

Corrupted Backup Files

Check gzip integrity: gzip -t /backup/app_db_20240114.sql.gz Inspect the first and last few lines after decompression to ensure no truncation.

Table Already Exists During Restore

Option 1: Drop the existing table before import.

Option 2: Regenerate dump with --add-drop-table to automatically drop.

Option 3: Import only data ( --no-create-info) if schema is unchanged.

innodb_log_file_size Mismatch (XtraBackup)

Compare backup-my.cnf inside the backup with the current MySQL my.cnf. Adjust innodb_log_file_size in the target server and restart before --copy-back.

Missing or Corrupted Binlog

If a binlog file is unreadable, you cannot replay events from that point. Identify the last good binlog and resume PITR from the previous full backup. This underscores the need for off‑site binlog copies.

mysqldump Locked by Long‑Running Transaction

Check for running InnoDB transactions:

SELECT * FROM information_schema.INNODB_TRX WHERE trx_state='RUNNING';

Kill offending transactions only after confirming they are not legitimate business work.

Replication Lag After Restore

After restoring the primary, the replica may lag. Increase slave_parallel_workers and set slave_parallel_type=LOGICAL_CLOCK (MySQL 5.7+) or binlog_transaction_dependency_tracking=WRITESET (MySQL 8.0) to improve parallelism.

Partial Data After Restore

Root causes include:

Using --single-transaction while a long transaction was active.

Running DDL during backup.

Backup file truncated due to disk or network failure.

Mitigation: avoid DDL during backup windows, verify backup size, run gzip -t, and perform regular restore drills.

Backup Strategy Design Best Practices

Tool Combination : Small databases – mysqldump + binlog; Large databases – XtraBackup full + incremental + binlog.

Frequency : Daily full at low‑traffic time; hourly or 15‑min binlog; incremental every 6 h for large sets.

Monitoring : Ensure jobs run, file size thresholds, integrity checks, and alerting.

Security : Permissions 600, encryption, off‑site copies, minimal‑privilege backup user.

Recovery Verification : Monthly full restore, quarterly disaster drills, record RTO.

Conclusion

MySQL backup and recovery demand a systematic approach rather than ad‑hoc commands. Selecting the right tool ( mysqldump vs XtraBackup), designing a backup cadence that meets RPO/RTO, automating the process with robust logging and alerting, and regularly validating restores are the pillars of a reliable data protection strategy. By following the step‑by‑step procedures, scripts, and best‑practice recommendations presented here, teams can move from "we have backups" to "we can confidently restore any point in time".

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

MaGe Linux Operations
Written by

MaGe Linux Operations

Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.