Master-Slave Replication Configuration in MySQL: Complete Setup Guide
Introduction
MySQL master-slave replication is a fundamental database architecture pattern that enables data from one MySQL database server (the master) to be automatically copied to one or more MySQL database servers (the slaves). This powerful feature provides numerous benefits including improved read performance through load distribution, enhanced data redundancy for disaster recovery, and the ability to perform backups without impacting the primary database server.
Replication works by recording all data changes on the master server in binary logs, which are then transmitted to slave servers and replayed to keep the data synchronized. This asynchronous process allows the master to continue operating independently while slaves catch up with changes, making it an ideal solution for read-heavy applications where the majority of database operations are SELECT queries.
Understanding and properly implementing MySQL replication is crucial for building scalable, high-availability database infrastructures. This comprehensive guide will walk you through every step of configuring master-slave replication, from initial server preparation to monitoring and troubleshooting, ensuring you can confidently deploy and manage replicated MySQL environments.
Prerequisites
Before beginning the replication configuration, ensure you have the following:
Server Requirements
- Two or more Linux servers (Ubuntu 20.04+, CentOS 7+, or Debian 10+)
- One server designated as the master
- One or more servers designated as slaves
- Network connectivity between all servers
- Sufficient bandwidth for replication traffic
MySQL Installation
- MySQL 5.7+ or MySQL 8.0+ installed on all servers
- MariaDB 10.3+ is also compatible
- Root or administrative access to MySQL on all servers
- MySQL service running and accessible
System Requirements
- At least 2GB RAM per server (4GB+ recommended)
- Adequate disk space for database storage and binary logs
- Static IP addresses or reliable DNS names for all servers
- Synchronized system clocks (NTP recommended)
Firewall Configuration
- Port 3306 open between master and slave servers
- SSH access (port 22) for server management
Knowledge Requirements
- Basic MySQL administration skills
- Understanding of SQL syntax
- Linux command line proficiency
- Basic networking concepts
Understanding MySQL Replication
Replication Architecture
MySQL replication uses a binary log (binlog) based approach:
- The master records all data changes in binary logs
- Slaves connect to the master and request binary log events
- The master sends binary log events to connected slaves
- Slaves receive events and store them in relay logs
- A SQL thread on each slave reads and executes relay log events
Replication Formats
MySQL supports three binary log formats:
Statement-Based Replication (SBR): Logs SQL statements. More compact but can cause inconsistencies with non-deterministic functions.
Row-Based Replication (RBR): Logs individual row changes. More reliable and consistent but generates larger logs.
Mixed Replication: Automatically switches between statement-based and row-based formats depending on the operation.
Replication Topology
Common replication topologies include:
- Single Master, Multiple Slaves: One master handles writes, multiple slaves handle reads
- Chain Replication: Master replicates to intermediate slaves, which replicate to additional slaves
- Master-Master: Two servers acting as both master and slave (advanced configuration)
Step-by-Step Configuration
Step 1: Configure the Master Server
First, connect to your master server and modify the MySQL configuration file.
For Ubuntu/Debian:
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
For CentOS/RHEL:
sudo nano /etc/my.cnf
Add or modify the following configuration under the [mysqld] section:
[mysqld]
# Server identification
server-id = 1
# Enable binary logging
log_bin = /var/log/mysql/mysql-bin.log
# Binary log format (ROW is recommended)
binlog_format = ROW
# Databases to replicate (optional - omit to replicate all)
# binlog_do_db = database1
# binlog_do_db = database2
# Databases to ignore (optional)
# binlog_ignore_db = mysql
# binlog_ignore_db = information_schema
# Binary log retention period (days)
expire_logs_days = 10
# Maximum binary log size before rotation
max_binlog_size = 100M
# Enable GTID for easier failover (MySQL 5.6+)
gtid_mode = ON
enforce_gtid_consistency = ON
# Ensure binary logs are sync'd to disk
sync_binlog = 1
# InnoDB settings for durability
innodb_flush_log_at_trx_commit = 1
Save the file and restart MySQL:
sudo systemctl restart mysql
Verify MySQL is running:
sudo systemctl status mysql
Step 2: Create Replication User on Master
Connect to MySQL on the master server:
mysql -u root -p
Create a dedicated replication user with appropriate privileges:
-- Create replication user
CREATE USER 'replication_user'@'%' IDENTIFIED WITH mysql_native_password BY 'StrongPassword123!';
-- Grant replication privileges
GRANT REPLICATION SLAVE ON *.* TO 'replication_user'@'%';
-- Apply privilege changes
FLUSH PRIVILEGES;
For enhanced security, restrict the replication user to specific slave IP addresses:
-- Create replication user for specific slave
CREATE USER 'replication_user'@'192.168.1.20' IDENTIFIED WITH mysql_native_password BY 'StrongPassword123!';
GRANT REPLICATION SLAVE ON *.* TO 'replication_user'@'192.168.1.20';
FLUSH PRIVILEGES;
Step 3: Record Master Binary Log Position
While still connected to the master MySQL server, lock the tables and get the binary log position:
-- Lock tables to prevent writes
FLUSH TABLES WITH READ LOCK;
-- Get current binary log file and position
SHOW MASTER STATUS;
You'll see output similar to:
+------------------+----------+--------------+------------------+-------------------+
| File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 | 154 | | | |
+------------------+----------+--------------+------------------+-------------------+
Important: Write down the File name and Position number. You'll need these values when configuring the slave. Keep the MySQL session open with tables locked while you create the backup.
Step 4: Create Master Database Backup
Open a new terminal session to the master server and create a backup:
# Create backup directory
sudo mkdir -p /var/backups/mysql
# Create full database dump
sudo mysqldump -u root -p \
--all-databases \
--master-data=2 \
--single-transaction \
--flush-logs \
--triggers \
--routines \
--events \
> /var/backups/mysql/master_backup.sql
For large databases, add compression:
sudo mysqldump -u root -p \
--all-databases \
--master-data=2 \
--single-transaction \
--flush-logs \
--triggers \
--routines \
--events | gzip > /var/backups/mysql/master_backup.sql.gz
After the backup completes, return to your MySQL session and unlock the tables:
UNLOCK TABLES;
Step 5: Transfer Backup to Slave Server
Transfer the backup file to your slave server:
# Using scp
scp /var/backups/mysql/master_backup.sql root@slave_server_ip:/tmp/
# Or with compression
scp /var/backups/mysql/master_backup.sql.gz root@slave_server_ip:/tmp/
Alternatively, use rsync for large files:
rsync -avz --progress /var/backups/mysql/master_backup.sql root@slave_server_ip:/tmp/
Step 6: Configure the Slave Server
Connect to your slave server and edit the MySQL configuration file:
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
Add the following configuration under [mysqld]:
[mysqld]
# Server identification (must be unique)
server-id = 2
# Enable relay log
relay-log = /var/log/mysql/mysql-relay-bin
# Binary logging on slave (optional, for cascading replication)
log_bin = /var/log/mysql/mysql-bin.log
binlog_format = ROW
# Make slave read-only to prevent accidental writes
read_only = 1
# Relay log settings
relay_log_recovery = 1
relay_log_purge = 1
# Enable GTID (must match master)
gtid_mode = ON
enforce_gtid_consistency = ON
# Skip errors (use cautiously)
# slave_skip_errors = 1062,1032
# Replication filters (optional)
# replicate_do_db = database1
# replicate_ignore_db = mysql
Save the configuration and restart MySQL:
sudo systemctl restart mysql
Step 7: Restore Master Backup on Slave
Connect to the slave server and import the master backup:
# If backup is compressed
gunzip /tmp/master_backup.sql.gz
# Import the backup
mysql -u root -p < /tmp/master_backup.sql
This process may take several minutes to hours depending on database size.
Step 8: Configure Replication on Slave
Connect to MySQL on the slave server:
mysql -u root -p
Configure the slave to connect to the master:
-- Stop slave if running
STOP SLAVE;
-- Configure master connection
CHANGE MASTER TO
MASTER_HOST='master_server_ip',
MASTER_USER='replication_user',
MASTER_PASSWORD='StrongPassword123!',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=154;
-- Start slave replication
START SLAVE;
-- Check slave status
SHOW SLAVE STATUS\G
If using GTID-based replication (recommended for MySQL 5.6+):
STOP SLAVE;
CHANGE MASTER TO
MASTER_HOST='master_server_ip',
MASTER_USER='replication_user',
MASTER_PASSWORD='StrongPassword123!',
MASTER_AUTO_POSITION=1;
START SLAVE;
SHOW SLAVE STATUS\G
Step 9: Verify Replication Status
Check the slave status output for key indicators:
SHOW SLAVE STATUS\G
Look for these critical values:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Seconds_Behind_Master: 0
Last_IO_Error:
Last_SQL_Error:
Both Slave_IO_Running and Slave_SQL_Running must be "Yes" for successful replication.
Step 10: Test Replication
On the master server, create a test database and table:
-- Connect to master
CREATE DATABASE replication_test;
USE replication_test;
CREATE TABLE test_table (
id INT PRIMARY KEY AUTO_INCREMENT,
test_data VARCHAR(100),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO test_table (test_data) VALUES ('Test replication data');
On the slave server, verify the data has been replicated:
-- Connect to slave
USE replication_test;
SELECT * FROM test_table;
You should see the data that was inserted on the master.
Advanced Configuration
Setting Up Multiple Slaves
To add additional slaves, repeat steps 6-10 for each new slave server, ensuring each has a unique server-id.
For the second slave, use:
server-id = 3
For the third slave:
server-id = 4
Implementing Semi-Synchronous Replication
Semi-synchronous replication provides better data safety by ensuring at least one slave receives the binary log before the master commits:
On the master:
-- Install plugin
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
-- Enable semi-sync
SET GLOBAL rpl_semi_sync_master_enabled = 1;
-- Set timeout (milliseconds)
SET GLOBAL rpl_semi_sync_master_timeout = 1000;
-- Verify status
SHOW VARIABLES LIKE 'rpl_semi_sync%';
On each slave:
-- Install plugin
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
-- Enable semi-sync
SET GLOBAL rpl_semi_sync_slave_enabled = 1;
-- Restart slave threads
STOP SLAVE IO_THREAD;
START SLAVE IO_THREAD;
-- Verify status
SHOW VARIABLES LIKE 'rpl_semi_sync%';
Delayed Replication
Configure delayed replication to protect against accidental data deletion:
-- On slave server
STOP SLAVE;
-- Set 1-hour delay
CHANGE MASTER TO MASTER_DELAY = 3600;
START SLAVE;
-- Verify delay
SHOW SLAVE STATUS\G
Parallel Replication
Enable parallel replication for better performance on multi-core systems (MySQL 5.7+):
On slave:
STOP SLAVE SQL_THREAD;
SET GLOBAL slave_parallel_type = 'LOGICAL_CLOCK';
SET GLOBAL slave_parallel_workers = 4;
START SLAVE SQL_THREAD;
Monitoring and Maintenance
Monitor Replication Lag
Create a monitoring script:
sudo nano /usr/local/bin/check-replication-lag.sh
#!/bin/bash
SLAVE_STATUS=$(mysql -e "SHOW SLAVE STATUS\G")
LAG=$(echo "$SLAVE_STATUS" | grep "Seconds_Behind_Master" | awk '{print $2}')
if [ "$LAG" = "NULL" ]; then
echo "ERROR: Replication is not running!"
exit 2
elif [ "$LAG" -gt 300 ]; then
echo "WARNING: Replication lag is ${LAG} seconds"
exit 1
else
echo "OK: Replication lag is ${LAG} seconds"
exit 0
fi
Make it executable:
sudo chmod +x /usr/local/bin/check-replication-lag.sh
Monitor Binary Log Size
On the master, monitor binary log disk usage:
sudo du -sh /var/log/mysql/
Configure automatic binary log purging:
-- Keep logs for 7 days
SET GLOBAL expire_logs_days = 7;
-- Or specify in days and hours (MySQL 8.0+)
SET GLOBAL binlog_expire_logs_seconds = 604800;
Create Monitoring Dashboard
Monitor key replication metrics:
-- Check replication status
SHOW SLAVE STATUS\G
-- View relay log position
SHOW RELAYLOG EVENTS;
-- Check binary log position on master
SHOW MASTER STATUS;
-- View replication errors
SELECT * FROM performance_schema.replication_applier_status_by_worker;
Verification and Testing
Verify Slave Configuration
-- Check slave is read-only
SHOW VARIABLES LIKE 'read_only';
-- Verify GTID status
SHOW VARIABLES LIKE 'gtid%';
-- Check relay log configuration
SHOW VARIABLES LIKE 'relay%';
Test Failover Readiness
Simulate master failure:
# On master
sudo systemctl stop mysql
On slave, promote to master:
-- Stop replication
STOP SLAVE;
-- Reset slave status
RESET SLAVE ALL;
-- Disable read-only mode
SET GLOBAL read_only = 0;
-- Verify promotion
SHOW MASTER STATUS;
Verify Data Consistency
Use pt-table-checksum from Percona Toolkit:
# Install Percona Toolkit
sudo apt-get install percona-toolkit
# Run checksum
pt-table-checksum --host=master_server --databases=your_database
Troubleshooting
Replication Not Starting
Issue: Slave_IO_Running or Slave_SQL_Running shows "No"
Solution: Check error logs and slave status:
SHOW SLAVE STATUS\G
Look at Last_IO_Error and Last_SQL_Error fields. Common causes include:
# Check network connectivity
ping master_server_ip
telnet master_server_ip 3306
# Verify credentials
mysql -h master_server_ip -u replication_user -p
# Check firewall
sudo ufw status
sudo firewall-cmd --list-all
Duplicate Key Errors
Issue: Error 1062: Duplicate entry
Solution: Skip the duplicate error:
-- Stop slave
STOP SLAVE;
-- Skip one error
SET GLOBAL sql_slave_skip_counter = 1;
-- Restart slave
START SLAVE;
-- Verify status
SHOW SLAVE STATUS\G
For GTID-based replication:
STOP SLAVE;
SET GTID_NEXT='problematic_gtid';
BEGIN;
COMMIT;
SET GTID_NEXT='AUTOMATIC';
START SLAVE;
Replication Lag Issues
Issue: High Seconds_Behind_Master value
Solution: Investigate and optimize:
-- Check slow queries on slave
SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 1;
-- Enable parallel replication
STOP SLAVE SQL_THREAD;
SET GLOBAL slave_parallel_workers = 4;
START SLAVE SQL_THREAD;
-- Check for table locks
SHOW PROCESSLIST;
Binary Log File Not Found
Issue: Error: "Could not find first log file"
Solution: Reset slave and reconfigure:
STOP SLAVE;
RESET SLAVE;
-- Reconfigure with current master position
CHANGE MASTER TO
MASTER_LOG_FILE='current_bin_file',
MASTER_LOG_POS=current_position;
START SLAVE;
Connection Timeouts
Issue: Lost connection to MySQL server during query
Solution: Adjust timeout settings:
-- On slave
SET GLOBAL slave_net_timeout = 60;
-- In my.cnf
[mysqld]
slave_net_timeout = 60
Best Practices
1. Use GTID-Based Replication
Global Transaction Identifiers (GTIDs) simplify replication management and make failover easier. Always enable GTID for new setups.
2. Implement Monitoring and Alerting
Set up automated monitoring for:
- Replication lag (Seconds_Behind_Master)
- Slave thread status (IO and SQL threads)
- Binary log disk usage
- Network connectivity
- Error logs
3. Regular Backup Testing
Test slave backups regularly to ensure they're consistent and restorable. Perform test restores on a separate server monthly.
4. Document Your Replication Topology
Maintain clear documentation of:
- Server roles and IP addresses
- Replication configuration
- Failover procedures
- Contact information for database administrators
5. Secure Replication Traffic
Use SSL/TLS for replication traffic in production:
CHANGE MASTER TO
MASTER_HOST='master_server_ip',
MASTER_USER='replication_user',
MASTER_PASSWORD='password',
MASTER_SSL=1,
MASTER_SSL_CA='/path/to/ca.pem',
MASTER_SSL_CERT='/path/to/client-cert.pem',
MASTER_SSL_KEY='/path/to/client-key.pem';
6. Plan for Capacity
Monitor disk space for binary and relay logs. Configure automatic log rotation and purging to prevent disk space issues.
7. Use Read-Only Mode on Slaves
Always configure slaves as read-only to prevent accidental writes:
SET GLOBAL read_only = 1;
SET GLOBAL super_read_only = 1; -- MySQL 5.7.8+
8. Implement Connection Pooling
Use connection pooling in your application layer to efficiently distribute read queries across multiple slaves.
9. Monitor Performance Impact
Replication can impact master performance. Monitor:
- Binary log generation rate
- Network bandwidth usage
- Disk I/O for binary logs
10. Have a Failover Plan
Document and regularly test your failover procedures:
- Promoting a slave to master
- Redirecting application traffic
- Reconfiguring remaining slaves
- Bringing old master back online
Conclusion
MySQL master-slave replication is a powerful feature that enables scalable, highly available database architectures. By following this comprehensive guide, you've learned how to configure, maintain, and troubleshoot MySQL replication from basic setup through advanced configurations.
Key accomplishments include setting up binary logging on the master, creating dedicated replication users with appropriate privileges, configuring one or more slave servers, implementing monitoring and alerting systems, and understanding how to troubleshoot common replication issues. You've also learned best practices for maintaining a healthy replication environment and ensuring data consistency across your database infrastructure.
Replication is not a replacement for backups, but rather a complementary technology that improves availability and read scalability. Continue to maintain regular backups of both master and slave servers, monitor replication lag and status regularly, test failover procedures periodically, and stay updated with MySQL security patches and updates.
As your infrastructure grows, consider more advanced topologies such as multi-source replication, group replication for automatic failover, or hybrid solutions combining replication with clustering technologies. The foundation you've built with this guide will serve you well as you scale and evolve your database architecture to meet increasing demands.


