Percona XtraBackup is an open-source hot backup utility for MySQL and Percona Server that performs physical backups without locking tables or interrupting active queries on InnoDB tables. Unlike mysqldump, which produces logical SQL dumps, XtraBackup copies InnoDB data files directly and replays the transaction log to bring the backup to a consistent state, making it far faster for large databases. It supports full backups, incremental backups based on LSN (Log Sequence Number), and streaming backups to remote storage. This tutorial covers installing Percona XtraBackup 8.0 on RHEL 8 and performing full, incremental, and restore operations.
Prerequisites
- RHEL 8 server running MySQL 8.0 or Percona Server 8.0
- Root or
sudoprivileges - Sufficient disk space — backup directory needs at least as much free space as the MySQL data directory
- A MySQL user with the following privileges:
BACKUP_ADMIN,PROCESS,RELOAD,LOCK TABLES,REPLICATION CLIENT
Step 1 — Install the Percona Repository and XtraBackup
Percona provides an official repository tool that configures the correct RPM repo for your OS version. Install it first, then use dnf to install XtraBackup 8.0.
# Download and install the Percona repository package
dnf install -y https://repo.percona.com/yum/percona-release-latest.noarch.rpm
# Enable the Percona XtraBackup 8.0 repository
percona-release enable-only tools release
# Install XtraBackup
dnf install -y percona-xtrabackup-80
# Verify the installed version
xtrabackup --version
Step 2 — Create a Dedicated Backup User
Create a MySQL user with the minimum required privileges for XtraBackup. Using a dedicated backup user rather than root follows the principle of least privilege.
mysql -u root -p << 'SQL'
CREATE USER 'xtrabackup'@'localhost' IDENTIFIED BY 'StrongBackupPass123!';
GRANT BACKUP_ADMIN, PROCESS, RELOAD, LOCK TABLES, REPLICATION CLIENT ON *.* TO 'xtrabackup'@'localhost';
FLUSH PRIVILEGES;
SQL
Step 3 — Take a Full Backup
The --backup flag copies InnoDB data files and logs to the target directory. The backup is not yet in a consistent state at this point — the prepare step handles that.
# Create the backup destination directory
mkdir -p /backup/full
# Run the full backup
xtrabackup
--backup
--user=xtrabackup
--password='StrongBackupPass123!'
--target-dir=/backup/full
# The backup is complete when you see:
# "completed OK!" at the end of output
# Review backup metadata
cat /backup/full/xtrabackup_info
Step 4 — Prepare the Full Backup
The prepare step applies the InnoDB transaction log to the data files, rolling back uncommitted transactions and making the backup crash-consistent. This must be done before restoration. When planning incremental backups, add --apply-log-only here to preserve future incremental merging.
# Prepare the full backup (makes it consistent)
xtrabackup --prepare --target-dir=/backup/full
# Output ends with:
# "completed OK!"
# The backup is now ready to restore
Step 5 — Take and Prepare Incremental Backups
Incremental backups copy only InnoDB pages modified since the base backup, identified by comparing LSN values. Chain them back to the full backup using --incremental-basedir.
# First incremental — based on the full backup
mkdir -p /backup/inc1
xtrabackup
--backup
--user=xtrabackup
--password='StrongBackupPass123!'
--target-dir=/backup/inc1
--incremental-basedir=/backup/full
# Second incremental — based on inc1
mkdir -p /backup/inc2
xtrabackup
--backup
--user=xtrabackup
--password='StrongBackupPass123!'
--target-dir=/backup/inc2
--incremental-basedir=/backup/inc1
# Prepare: re-prepare full with --apply-log-only, then merge incrementals
xtrabackup --prepare --apply-log-only --target-dir=/backup/full
xtrabackup --prepare --apply-log-only
--target-dir=/backup/full
--incremental-dir=/backup/inc1
# Last incremental does NOT use --apply-log-only
xtrabackup --prepare
--target-dir=/backup/full
--incremental-dir=/backup/inc2
Step 6 — Restore the Backup
Stop MySQL, clear the existing data directory, then copy the prepared backup files back. Use xtrabackup --copy-back or rsync for the file transfer, then fix ownership before restarting MySQL.
# Stop MySQL before restoring
systemctl stop mysqld
# Empty the data directory (adjust path if different)
rm -rf /var/lib/mysql/*
# Method 1 — use xtrabackup copy-back
xtrabackup --copy-back --target-dir=/backup/full
# Method 2 — use rsync (faster for large datasets)
# rsync -avrP /backup/full/ /var/lib/mysql/
# Fix file ownership — MySQL runs as the mysql user
chown -R mysql:mysql /var/lib/mysql
# Start MySQL and verify
systemctl start mysqld
systemctl status mysqld
mysql -u root -p -e "SHOW DATABASES;"
Conclusion
You have set up a complete backup strategy for MySQL 8.0 on RHEL 8 using Percona XtraBackup, covering full backups, incremental backups chained by LSN, and the two-phase prepare-then-restore workflow. Because XtraBackup operates at the physical file level rather than generating SQL, backup and restore times scale with data file size rather than row count, making it significantly faster than mysqldump for databases in the tens or hundreds of gigabytes. Incorporating this into a nightly cron job with offsite copies to object storage provides a robust, low-RTO recovery capability.
Next steps: How to Stream XtraBackup to Amazon S3 on RHEL 8, How to Automate MySQL Backups with Cron on RHEL 8, and How to Encrypt XtraBackup Archives on RHEL 8.