基于 CentOS 7 的完整、详细、可直接执行的 MySQL 8.0 主从复制部署流程
适用版本:CentOS 7(最小安装即可)
架构:1 主 + 1 从
特性:GTID + 半同步复制 + 自动备份 + 安全加固
第一步:基础环境准备(两台服务器均执行)
1. 设置主机名
bash
# 主库执行
sudo hostnamectl set-hostname db-master
# 从库执行
sudo hostnamectl set-hostname db-slave
2. 配置时间同步
bash
sudo timedatectl set-timezone Asia/Shanghai
sudo yum install -y chrony
sudo systemctl enable --now chronyd
timedatectl status # 确认 "System clock synchronized: yes"

3. 关闭 SELinux(可选,避免权限问题)
bash
sudo setenforce 0
sudo sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
4. 配置防火墙(可选,仅放行内网访问 3306)
创建脚本 setup_firewall.sh:
bash
#!/bin/bash
# setup_firewall.sh
INTERNAL_NET="10.0.0.0/16" # 根据实际调整,覆盖主从 IP 段
sudo systemctl enable --now firewalld
sudo firewall-cmd --permanent --add-rich-rule="rule family=\"ipv4\" source address=\"${INTERNAL_NET}\" port protocol=\"tcp\" port=\"3306\" accept"
sudo firewall-cmd --reload
echo "防火墙已限制仅 ${INTERNAL_NET} 可访问 MySQL"
执行:
bash
chmod +x setup_firewall.sh && sudo ./setup_firewall.sh
第二步:安装 MySQL 8.0(两台服务器均执行)
1. 卸载可能存在的 MariaDB
bash
sudo yum remove -y mariadb-libs
2. 安装 MySQL 官方 EL7 仓库
bash
sudo rpm -Uvh https://dev.mysql.com/get/mysql80-community-release-el7-11.noarch.rpm
注意:必须是 el7,不是 el8!

3. 安装 MySQL Server
bash
sudo yum install -y mysql-community-server
这里可能会存在安装失败的可能,原因是实际拉取是el8
yum --assumeno install mysql-community-server | grep "Package.*will be installed"
解决方法
# 1. 卸载可能存在的 el8 仓库
sudo rpm -e $(rpm -qa | grep mysql.*community.*release) 2>/dev/null
# 2. 重新安装 el7 仓库
sudo rpm -Uvh https://dev.mysql.com/get/mysql80-community-release-el7-11.noarch.rpm
# 3. 强制锁定 baseurl 到 el7
sudo sed -i 's|baseurl=.*|baseurl=https://repo.mysql.com/yum/mysql-8.0-community/el/7/$basearch/|' /etc/yum.repos.d/mysql-community.repo
# 4. 清理缓存
sudo yum clean all && sudo rm -rf /var/cache/yum
# 5. 验证
yum info mysql-community-server | grep -E "Version|Release|From repo"
# 应显示 Release: 1.el7

4. 启动并设置开机自启
bash
sudo systemctl enable --now mysqld
5. 获取临时 root 密码vvvv(主库重做,从库到这里)
bash
TEMP_PASS=$(sudo grep 'temporary password' /var/log/mysqld.log | awk '{print $NF}')
echo "临时密码: $TEMP_PASS"
第三步:安全初始化(两台服务器均执行)
创建脚本 secure_mysql.sh:
vi secure_mysql.sh
内容如下:
bash
#!/bin/bash
ROOT_PASS="MySQLPass@2025!"
TEMP_PASS=$(sudo grep 'temporary password' /var/log/mysqld.log | awk '{print $NF}')
mysql -u root -p"$TEMP_PASS" --connect-expired-password << EOF
ALTER USER 'root'@'localhost' IDENTIFIED BY '${ROOT_PASS}';
DELETE FROM mysql.user WHERE User='';
DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');
DROP DATABASE IF EXISTS test;
DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%';
FLUSH PRIVILEGES;
EOF
echo "安全初始化完成。root 密码: ${ROOT_PASS}"
执行:
bash
chmod +x secure_mysql.sh && sudo ./secure_mysql.sh

第四步:主库配置(仅在 db-master 执行)
1. 创建慢日志目录
bash
sudo mkdir -p /var/log/mysql
sudo chown mysql:mysql /var/log/mysql
sudo chmod 750 /var/log/mysql
sudo touch /var/log/mysql-slow.log
sudo chown mysql:mysql /var/log/mysql-slow.log
sudo chmod 640 /var/log/mysql-slow.log
2. 编辑 /etc/my.cnf
vi /etc/my.cnf
内容如下:
ini
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
server-id=1
# Binlog
log-bin=mysql-bin
binlog_format=ROW
expire_logs_days=7
max_binlog_size=1G
# GTID
gtid_mode=ON
enforce_gtid_consistency=ON
# 半同步
plugin_load_add='rpl_semi_sync_master=semisync_master.so'
rpl_semi_sync_master_enabled=1
rpl_semi_sync_master_timeout=10000
# 日志
log_error=/var/log/mysqld.log
slow_query_log=ON
slow_query_log_file=/var/log/mysql-slow.log
long_query_time=1
# 安全
bind-address=0.0.0.0
skip_name_resolve=ON
symbolic-links=0

3. 重启 MySQL
bash
sudo systemctl restart mysqld
4. 创建复制用户(注意从库 IP)
sql
mysql -u root -p'MySQLPass@2025!' << EOF
-- 检查插件是否已加载
SELECT PLUGIN_NAME, PLUGIN_STATUS FROM information_schema.PLUGINS
WHERE PLUGIN_NAME = 'rpl_semi_sync_master';
-- 如果未安装,才执行 INSTALL(可选:跳过此步,直接启用)
-- INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
-- 直接启用即可(即使已安装,SET GLOBAL 不会报错)
SET GLOBAL rpl_semi_sync_master_enabled = 1;
-- 创建复制用户
CREATE USER IF NOT EXISTS 'repl'@'10.0.16.12' IDENTIFIED WITH mysql_native_password BY 'StrongReplPass2025!';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'10.0.16.12';
FLUSH PRIVILEGES;
EOF
IP替换为你的从库真实 IP

第五步:从库配置(仅在 db-slave 执行)
1. 同样创建慢日志目录(同上)
bash
sudo mkdir -p /var/log/mysql
sudo chown mysql:mysql /var/log/mysql
sudo chmod 750 /var/log/mysql
sudo touch /var/log/mysql-slow.log
sudo chown mysql:mysql /var/log/mysql-slow.log
sudo chmod 640 /var/log/mysql-slow.log
2. 编辑 /etc/my.cnf
vi /etc/my.cnf
内容如下:
ini
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
server-id=2
gtid_mode=ON
enforce_gtid_consistency=ON
read_only=ON
plugin_load_add='rpl_semi_sync_slave=semisync_slave.so'
rpl_semi_sync_slave_enabled=1
log_error=/var/log/mysqld.log
slow_query_log=ON
slow_query_log_file=/var/log/mysql-slow.log
long_query_time=1
bind-address = 0.0.0.0
skip_name_resolve=ON
symbolic-links=0
3. 重启 MySQL
bash
sudo systemctl restart mysqld
4. 配置主从复制
查询插件是否安装
mysql -u root -p'MySQLPass@2025!' << EOF
SELECT PLUGIN_NAME, PLUGIN_STATUS
FROM information_schema.PLUGINS
WHERE PLUGIN_NAME = 'rpl_semi_sync_slave';
EOF

观察查询出来的状态是否为ACTIVE,如果不是需要在下面的命令中添加 INSTALL,放在 SET GLOBAL rpl_semi_sync_slave_enabled = 1; 之前
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
执行复制,
sql
mysql -u root -p'MySQLPass@2025!' << EOF
SET GLOBAL rpl_semi_sync_slave_enabled = 1;
STOP SLAVE;
CHANGE MASTER TO
MASTER_HOST='10.0.4.16',
MASTER_USER='repl',
MASTER_PASSWORD='StrongReplPass2025!',
MASTER_AUTO_POSITION=1;
START SLAVE;
EOF
IP替换成主库IP
密码换成上面复制用户设置的密码

查询部分,可以不要,图中命令错了,以上面的文字命令为准
5. 验证复制状态
bash
mysql -u root -p'MySQLPass@2025!' -e "SHOW SLAVE STATUS\G" | grep -E "IO_Running|SQL_Running|Seconds_Behind_Master"
成功标志:
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Seconds_Behind_Master: 0

第六步:配置自动备份(仅主库执行)
1. 创建备份用户
sql
mysql -u root -p'MySQLPass@2025!' << EOF
CREATE USER 'backup'@'localhost' IDENTIFIED BY 'BackupPass2025!';
GRANT SELECT, RELOAD, SHOW DATABASES, LOCK TABLES, REPLICATION CLIENT, PROCESS ON *.* TO 'backup'@'localhost';
FLUSH PRIVILEGES;
EOF
2. 创建备份脚本 /opt/scripts/mysql_backup.sh
vi scripts/mysql_backup.sh
内容如下:
bash
#!/bin/bash
BACKUP_DIR="/backup/mysql"
DATE=$(date +%Y%m%d_%H%M)
LOG_FILE="/var/log/mysql_backup.log"
mkdir -p "$BACKUP_DIR"
/usr/bin/mysqldump \
--user=backup \
--password='BackupPass2025!' \
--single-transaction \
--master-data=2 \
--set-gtid-purged=ON \
--routines --triggers --all-databases --hex-blob \
> "${BACKUP_DIR}/mysql_full_${DATE}.sql" 2>> "$LOG_FILE"
if [ $? -eq 0 ]; then
gzip "${BACKUP_DIR}/mysql_full_${DATE}.sql"
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +30 -delete
echo "[$(date)] 备份成功" >> "$LOG_FILE"
else
echo "[$(date)] 备份失败" >> "$LOG_FILE"
exit 1
fi
3. 设置定时任务
bash
sudo mkdir -p /opt/scripts
sudo cp mysql_backup.sh /opt/scripts/
sudo chmod +x /opt/scripts/mysql_backup.sh
echo "0 2 * * * root /opt/scripts/mysql_backup.sh" | sudo tee /etc/cron.d/mysql-backup

这里我是先创建脚本目录后,再写的脚本,所以这里就没有复制这个步骤
第七步:监控与日志轮转(从库执行)
1. 复制状态检查脚本(用于监控)
vi /usr/local/bin/check_replication.sh
内容如下:
bash
# /usr/local/bin/check_replication.sh
MYSQL_PASS="MySQLPass@2025!"
IO=$(mysql -u root -p"$MYSQL_PASS" -e "SHOW SLAVE STATUS\G" 2>/dev/null | grep "Slave_IO_Running:" | awk '{print $2}')
SQL=$(mysql -u root -p"$MYSQL_PASS" -e "SHOW SLAVE STATUS\G" 2>/dev/null | grep "Slave_SQL_Running:" | awk '{print $2}')
DELAY=$(mysql -u root -p"$MYSQL_PASS" -e "SHOW SLAVE STATUS\G" 2>/dev/null | grep "Seconds_Behind_Master:" | awk '{print $2}')
if [[ "$IO" == "Yes" && "$SQL" == "Yes" && "$DELAY" != "NULL" ]]; then
echo "replication_ok 1"
echo "seconds_behind $DELAY"
else
echo "replication_ok 0"
fi
目录授权
sudo chmod +x /usr/local/bin/check_replication.sh
2. 慢查询日志轮转
创建 /etc/logrotate.d/mysql:
vi /etc/logrotate.d/mysql
内容如下:
conf
/var/log/mysql-slow.log {
daily
missingok
rotate 60
compress
delaycompress
notifempty
create 640 mysql mysql
postrotate
/usr/bin/mysql -u root -p'MySQLPass@2025!' -e 'SELECT 1;' > /dev/null 2>&1 || true
endscript
}
第八步:手动高可用切换预案(从库执行)
创建 /opt/scripts/promote_to_master.sh:
sudo mkdir -p /opt/scripts
vi /opt/scripts/promote_to_master.sh
内容如下:
bash
#!/bin/bash
MYSQL_PASS="MySQLPass@2025!"
mysql -u root -p"$MYSQL_PASS" << EOF
STOP SLAVE;
RESET SLAVE ALL;
SET GLOBAL read_only = OFF;
EOF
# 可选:更新 server-id(避免未来冲突)
sudo sed -i 's/server-id=2/server-id=1/' /etc/my.cnf
sudo systemctl restart mysqld
NEW_IP=$(ip route get 1 | awk '{print $7; exit}')
echo "已提升为新主库!请将应用写地址切换至 $NEW_IP"
sudo chmod +x /opt/scripts/promote_to_master.sh
原主库恢复后:清空
/var/lib/mysql,重新初始化或从备份恢复,再配置为新从库。
检查清单
| 项目 | 状态 |
|---|---|
| 主从 GTID 复制正常 | SHOW SLAVE STATUS |
| 半同步插件加载成功 | SHOW PLUGINS LIKE '%semi%' |
| 防火墙仅限内网 | firewall-cmd --list-all |
| root 无法远程登录 | SELECT host,user FROM mysql.user; |
| 每日备份可执行 | 检查 /backup/mysql/ |
| 慢日志权限正确 | ls -l /var/log/mysql-slow.log |
| 时间同步正常 | chronyc sources -v |
远程连接(主库执行,从库会自动复制)
创建专属远程连接的用户catgod007,授予完整常用开发权限组合,之前的用户均不能远程登录
CREATE USER 'catgod007'@'%' IDENTIFIED BY 'StrongAdminPass@2025!';
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER,INDEX ON *.* TO 'catgod007'@'%';
FLUSH PRIVILEGES;
权限说明
权限 能做什么 典型场景 SELECT查数据 查询用户信息 INSERT插入新记录 注册新用户 UPDATE修改记录 更新资料 DELETE删除记录 删除订单 CREATE建库/建表 初始化 schema DROP删库/删表 清理测试数据 ALTER改表结构 加新字段 INDEX建/删索引 优化查询性能
菜鸡说
- 从库执行同步后,后续写相关的命令直接写在主库,从库用于查看即可,否则会造成你将命令在主从库都执行后,从库同步时会发生冲突导致从库无法复制主库。
- 遇到问题问AI,解决问题的速度,比你去找各种解决方式要快得多,前提是你描述问题比较细致,像我这篇文章,遇到问题,你直接发给AI,让它帮你解决问题