主从复制成功需满足三条件:主库启用ROW格式binlog、主从server-id唯一、从库CHANGE MASTER TO参数准确。任一错误将导致Slave_IO_Running或Slave_SQL_Running为No。

主从复制能跑起来,核心就三件事:主库开 binlog、主从 server-id 不重复、从库 CHANGE MASTER TO 参数填对。其他都是围绕这三点展开的细节,填错任意一个,SHOW SLAVE STATUS\G 里 Slave_IO_Running 或 Slave_SQL_Running 就会是 No。
主库必须启用 binlog 且格式合理
MySQL 5.7+ 默认 binlog_format 是 STATEMENT,但实际生产中强烈建议设为 ROW。原因很简单:STATEMENT 在函数、临时表、非确定性语句(如 NOW()、UUID())下容易导致主从数据不一致。
配置项加在 /etc/my.cnf 的 [mysqld] 段里:
[mysqld] server-id = 1 log-bin = /var/log/mysql/mysql-bin.log binlog-format = ROW expire_logs_days = 7
注意:log-bin 路径需确保 MySQL 进程有写权限;expire_logs_days 非必需但建议加,避免磁盘被旧 binlog 塞满。
改完必须重启服务:sudo systemctl restart mysql。验证是否生效:
mysql -uroot -p -e "SHOW VARIABLES LIKE 'log_bin';" → 返回 ON
mysql -uroot -p -e "SHOW VARIABLES LIKE 'binlog_format';" → 返回 ROW
主从 server-id 绝对不能相同
这是最常踩的坑。错误现象是:START SLAVE 后立刻报错 Fatal error: The slave I/O thread stops because master and slave have equal MySQL server ids。
解决方法非常直接:
- 主库
server-id设为非 0 整数,比如1、101(推荐用 IP 最后一段,如192.168.1.104→104) - 从库
server-id必须不同,且不能为 0 —— 即使只有一台从库,也得设成2、105等 - 如果从库是克隆主库数据目录得来的,还要检查
datadir/auto.cnf里的server-uuid,它也必须唯一,否则会卡在IO_THREAD启动阶段
改完同样要重启 MySQL,然后确认:
mysql -uroot -p -e "SHOW VARIABLES LIKE 'server_id';"
从库 CHANGE MASTER TO 的参数怎么填才不翻车
CHANGE MASTER TO 是从库连上主库的“握手协议”,四个关键参数缺一不可,且必须和主库当前状态严格匹配:
-
MASTER_HOST:主库 IP,**不能写 localhost 或 127.0.0.1**(除非从库也在主库本机,且明确走 TCP) -
MASTER_USER和MASTER_PASSWORD:主库上用GRANT REPLICATION SLAVE ON *.*创建的专用账号,**不是 root** -
MASTER_LOG_FILE和MASTER_LOG_POS:必须来自主库执行SHOW MASTER STATUS;的实时输出,**不能抄旧值、不能猜、不能用备份时的快照**
典型操作链(主库上执行):
FLUSH TABLES WITH READ LOCK; → 锁表防写入
SHOW MASTER STATUS; → 记下 File(如 mysql-bin.000003)和 Position(如 154)
UNLOCK TABLES; → 解锁
然后在从库执行:
CHANGE MASTER TO MASTER_HOST='192.168.1.104', MASTER_USER='repl', MASTER_PASSWORD='pass123', MASTER_LOG_FILE='mysql-bin.000003', MASTER_LOG_POS=154;
注意:MASTER_LOG_POS 是纯数字,不要加引号;文件名带引号是安全的,但不加也行。
启动后为什么 IO 或 SQL 线程还是 No
执行 START SLAVE; 后,立刻查状态:
SHOW SLAVE STATUS\G
重点盯两个字段:
-
Slave_IO_Running: No→ 多半是网络不通(主库 3306 未开放)、账号密码错、MASTER_HOST写错、或主库没开log-bin -
Slave_SQL_Running: No→ 多半是 SQL 冲突(从库已有同名库表)、主库执行了DROP DATABASE但从库没该库、或relay-log损坏。此时看Last_SQL_Error字段,里面是真实报错
常见修复动作:
- 网络问题:在从库执行
telnet 192.168.1.104 3306看通不通 - 权限问题:主库重跑
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.1.%'; FLUSH PRIVILEGES; - SQL 报错且可跳过:执行
SET GLOBAL sql_slave_skip_counter = 1; START SLAVE;(仅限测试环境,生产慎用)
真正麻烦的是 Seconds_Behind_Master 持续增长——说明从库 SQL 线程追不上,这时候得看慢查询、大事务、或是否启用了 read_only=1 但忘了关掉从库上的写操作。

















