Percona XtraBackup is the industry-standard open-source tool for online, non-blocking hot backups of MySQL and MariaDB InnoDB databases. Unlike mysqldump, which produces a logical SQL dump and requires more time for large databases, XtraBackup performs a physical backup — copying InnoDB data files directly while MySQL is running, without acquiring table locks that would block writes. This makes XtraBackup the preferred backup solution for large databases (100 GB+) that cannot tolerate even a brief write lock during backup. XtraBackup also supports incremental backups (only changed pages since the last backup) and streaming backups directly to a remote server. This guide covers installing Percona XtraBackup 8.0 on RHEL 9, performing full and incremental backups, and restoring from backup.

Prerequisites

  • MySQL 8 or MariaDB installed on RHEL 9
  • A MySQL user with BACKUP_ADMIN and REPLICATION CLIENT privileges

Step 1 — Install Percona XtraBackup

# Add the Percona repository
dnf install -y https://repo.percona.com/yum/percona-release-latest.noarch.rpm
percona-release enable-only tools release
dnf install -y percona-xtrabackup-80

xtrabackup --version

Step 2 — Create a Dedicated Backup User

mysql -u root -p <<'SQL'
CREATE USER 'xtrabackup'@'localhost' IDENTIFIED BY 'XtraBackupPass123!';
GRANT BACKUP_ADMIN, PROCESS, RELOAD, REPLICATION CLIENT ON *.* TO 'xtrabackup'@'localhost';
GRANT SELECT ON performance_schema.* TO 'xtrabackup'@'localhost';
FLUSH PRIVILEGES;
SQL

Step 3 — Full Backup

# Create the backup directory
BACKUP_DIR="/var/backups/xtrabackup"
mkdir -p "$BACKUP_DIR/full-$(date +%Y%m%d)"

# Run the full backup
xtrabackup --backup 
    --user=xtrabackup 
    --password=XtraBackupPass123! 
    --target-dir="$BACKUP_DIR/full-$(date +%Y%m%d)"

# Prepare the backup (apply transaction logs — required before restore)
xtrabackup --prepare --target-dir="$BACKUP_DIR/full-$(date +%Y%m%d)"

Step 4 — Incremental Backup

# Incremental backup — only pages changed since the full backup
xtrabackup --backup 
    --user=xtrabackup 
    --password=XtraBackupPass123! 
    --target-dir="$BACKUP_DIR/incr-$(date +%Y%m%d)" 
    --incremental-basedir="$BACKUP_DIR/full-$(date +%Y%m%d --date='yesterday')"

# Prepare incremental backup (apply to the full backup)
xtrabackup --prepare --apply-log-only --target-dir="$BACKUP_DIR/full-20241201"
xtrabackup --prepare --target-dir="$BACKUP_DIR/full-20241201" 
    --incremental-dir="$BACKUP_DIR/incr-20241202"

Step 5 — Restore from Backup

# CAUTION: Restore overwrites the MySQL data directory
# Stop MySQL and clear data directory
systemctl stop mysqld
rm -rf /var/lib/mysql/*

# Copy back the prepared backup
xtrabackup --copy-back --target-dir="$BACKUP_DIR/full-20241201"

# Fix ownership
chown -R mysql:mysql /var/lib/mysql/

# Start MySQL
systemctl start mysqld

Step 6 — Stream Backup to Remote Server

# Stream compressed backup directly to a remote server via SSH
xtrabackup --backup --stream=xbstream --user=xtrabackup --password=XtraBackupPass123! 
    | gzip | ssh [email protected] "cat > /var/backups/mysql-$(date +%Y%m%d).xbstream.gz"

Conclusion

Percona XtraBackup on RHEL 9 provides non-blocking, hot MySQL backups that do not impact write performance. The prepare step applies the InnoDB transaction log to the backup before restore, ensuring a consistent point-in-time snapshot. For large databases (100 GB+), the combination of weekly full backups and daily incremental backups minimises both backup time and storage requirements while providing granular recovery points.

Next steps: How to Back Up MySQL with mysqldump on RHEL 9, How to Configure MySQL Primary-Replica Replication on RHEL 9, and How to Monitor MySQL with Prometheus on RHEL 9.