How to Use Percona XtraBackup for MySQL Hot Backups on RHEL 7

Taking reliable backups of a live MySQL or MariaDB database without interrupting application traffic is a fundamental requirement for any production system. mysqldump works for small databases but locks tables and can run for hours on large datasets. Percona XtraBackup solves this problem by performing a hot backup — it copies InnoDB data files while the database is running, without any table locks, using InnoDB’s own crash recovery mechanism to produce a consistent snapshot. This guide covers installing Percona XtraBackup 2.4 on RHEL 7, performing full and incremental backups, preparing the backup for restoration, and restoring data to MySQL.

Prerequisites

  • RHEL 7 server with MySQL 5.7 or MariaDB 10.x already installed and running
  • Root or sudo access
  • A MySQL user with the necessary backup privileges
  • Sufficient disk space on the backup destination (at minimum equal to the size of /var/lib/mysql)
  • The Percona yum repository available (covered below)

Step 1: Add the Percona YUM Repository

Percona provides an official RPM repository for RHEL-based distributions. Install the Percona repository package, which configures yum with all Percona product channels.

sudo yum install -y 
  https://repo.percona.com/yum/percona-release-latest.noarch.rpm

Enable the Percona original release channel which provides XtraBackup 2.4:

sudo percona-release enable original release

Verify the repository is active:

sudo yum repolist | grep percona

Step 2: Install Percona XtraBackup 2.4

Install XtraBackup 2.4, which is compatible with MySQL 5.6 and 5.7. If you are running MySQL 8.0, use percona-xtrabackup-80 instead.

sudo yum install -y percona-xtrabackup-24

Confirm the installation:

xtrabackup --version

The output should show a version line such as xtrabackup version 2.4.28. XtraBackup also installs the helper utility innobackupex (a wrapper script), though direct use of the xtrabackup binary is preferred in 2.4+.

Step 3: Create a Dedicated Backup User

Create a MySQL user specifically for backups with the minimum required privileges. Never run backups as the root MySQL user in production.

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

Create a MySQL options file so you do not need to pass credentials on the command line (which would expose them in process listings):

sudo tee /root/.xtrabackup.cnf <<'EOF'
[xtrabackup]
user=xtrabackup
password=SecureBackupPass1!
EOF

sudo chmod 600 /root/.xtrabackup.cnf

Step 4: Perform a Full Backup

Create a directory for your backups and run xtrabackup --backup. The --target-dir must not already exist — XtraBackup will create it.

sudo mkdir -p /backups/mysql

sudo xtrabackup 
  --defaults-extra-file=/root/.xtrabackup.cnf 
  --backup 
  --target-dir=/backups/mysql/full_2026-05-17

During the backup, XtraBackup streams InnoDB data files and copies the binary log position. At the end you will see:

xtrabackup: Transaction log of lsn (XXXXXXX) to (XXXXXXX) was copied.

followed by:

completed OK!

The backup directory now contains a raw copy of the InnoDB data files and a xtrabackup_info file with metadata including the LSN (Log Sequence Number) at the time the backup ended.

Step 5: Prepare the Full Backup

A freshly taken XtraBackup is not immediately restorable. The data files may be in an inconsistent state because InnoDB transactions were in-flight during the copy. The --prepare step applies the redo log to make the backup consistent, similar to InnoDB crash recovery.

sudo xtrabackup 
  --prepare 
  --target-dir=/backups/mysql/full_2026-05-17

After --prepare completes with completed OK!, the backup is in a clean, crash-recovered state and is ready for restoration or for use as the base for incremental backups.

Step 6: Perform Incremental Backups

Incremental backups capture only the pages modified since the last backup by comparing InnoDB LSN values. They save disk space and reduce backup time for large databases.

Take the first incremental backup based on the full backup:

sudo xtrabackup 
  --defaults-extra-file=/root/.xtrabackup.cnf 
  --backup 
  --target-dir=/backups/mysql/inc_2026-05-17_1 
  --incremental-basedir=/backups/mysql/full_2026-05-17

Take a second incremental backup based on the first incremental:

sudo xtrabackup 
  --defaults-extra-file=/root/.xtrabackup.cnf 
  --backup 
  --target-dir=/backups/mysql/inc_2026-05-17_2 
  --incremental-basedir=/backups/mysql/inc_2026-05-17_1

Step 7: Prepare Incremental Backups for Restoration

To restore a chain of backups, you must prepare each backup in order using the --apply-log-only flag to prevent the redo log from being rolled forward prematurely. Apply the full backup with --apply-log-only first:

sudo xtrabackup 
  --prepare 
  --apply-log-only 
  --target-dir=/backups/mysql/full_2026-05-17

Apply each incremental backup on top of the full, still using --apply-log-only for all but the last incremental:

# Apply first incremental (with --apply-log-only if more incrementals follow)
sudo xtrabackup 
  --prepare 
  --apply-log-only 
  --target-dir=/backups/mysql/full_2026-05-17 
  --incremental-dir=/backups/mysql/inc_2026-05-17_1

# Apply second (final) incremental — omit --apply-log-only on the last one
sudo xtrabackup 
  --prepare 
  --target-dir=/backups/mysql/full_2026-05-17 
  --incremental-dir=/backups/mysql/inc_2026-05-17_2

After the final prepare, /backups/mysql/full_2026-05-17 contains the fully merged, consistent backup including all incremental changes.

Step 8: Restore the Backup to /var/lib/mysql

To restore, the MySQL data directory must be empty. Stop MySQL, move or empty the data directory, then use xtrabackup --copy-back to restore the files.

# Stop MySQL
sudo systemctl stop mysqld

# Rename the existing data directory as a safety measure
sudo mv /var/lib/mysql /var/lib/mysql.old

# Create a fresh empty data directory
sudo mkdir /var/lib/mysql

# Copy back the prepared backup
sudo xtrabackup 
  --copy-back 
  --target-dir=/backups/mysql/full_2026-05-17

The --copy-back operation reads the datadir path from /etc/my.cnf and copies all backup files there. If you want to move files instead of copying them (faster, but destroys the backup directory), use --move-back instead.

Step 9: Fix Ownership and Start MySQL

After the restore, all files in the data directory are owned by the user who ran XtraBackup (typically root). MySQL requires the data directory to be owned by the mysql user.

sudo chown -R mysql:mysql /var/lib/mysql

sudo systemctl start mysqld
sudo systemctl status mysqld

Verify the database is intact after restart:

mysql -u root -p -e "SHOW DATABASES;"
mysql -u root -p -e "SELECT table_schema, COUNT(*) AS tables FROM information_schema.tables GROUP BY table_schema;"

Step 10: Comparing XtraBackup with mysqldump

Understanding when to use each tool helps you design an appropriate backup strategy.

  • mysqldump — produces a portable SQL text file; works with any MySQL-compatible server; easy to restore individual tables; but requires table locks on MyISAM tables, can be very slow on large databases, and the output file grows proportionally to the dataset size. Best for databases under a few GB or when portability is required.
  • XtraBackup — performs a hot physical backup with no locking of InnoDB tables; backup speed is proportional to I/O throughput, not query complexity; supports incremental backups; restored directly to the data directory; but the backup is not portable across different major versions of MySQL. Best for databases over 10 GB or where zero-downtime backups are mandatory.

For complete coverage, many teams combine both: XtraBackup for daily full and hourly incremental backups, and mysqldump for weekly logical exports that can be loaded into a different MySQL version for migration or compliance purposes.

# Example mysqldump for comparison
mysqldump -u root -p 
  --single-transaction 
  --routines 
  --triggers 
  --all-databases | gzip > /backups/mysql/full_dump_$(date +%F).sql.gz

Conclusion

You have installed Percona XtraBackup 2.4 on RHEL 7 and worked through the full backup lifecycle: taking a full backup with --backup, preparing it for restoration with --prepare, extending the backup chain with incremental backups, merging the chain, restoring with --copy-back, correcting file ownership with chown mysql:mysql, and restarting the MySQL service with systemctl. XtraBackup is the industry-standard solution for MySQL hot backups in production environments where locking is unacceptable and backup windows are tight. Combining it with a retention policy, off-site storage, and periodic restoration tests gives you a robust and verifiable database backup strategy.