
为什么 Slave_SQL_Running 会变成 NO
根本原因不是网络断了或主库挂了,而是从库 SQL 线程在回放 relay log 时遇到了无法跳过的错误,比如主键冲突、字段类型不匹配、表不存在、触发器执行失败等。它和 Slave_IO_Running 是两套独立逻辑:IO 线程负责拉日志,SQL 线程负责执行,一个挂不影响另一个运行。
常见现象:SHOW SLAVE STATUS\G 中 Seconds_Behind_Master 停滞、Exec_Master_Log_Pos 不再推进、Relay_Log_Space 持续增长但没消耗。
-
Slave_SQL_Running_State显示Waiting for an event from Coordinator?其实是假象,得看Seconds_Behind_Master和Exec_Master_Log_Pos是否变化 - 错误通常记录在
mysql.err日志里,但更直接的是查SHOW SLAVE STATUS\G的Last_SQL_Error字段 - 不要只盯着
Seconds_Behind_Master: NULL—— 它可能只是 SQL 线程卡死后的残留显示
怎么安全跳过单条报错的 SQL(临时恢复)
跳过不是万能解法,但对主从数据一致性要求不高、且确认错误可忽略的场景(如重复插入测试数据),可用 sql_slave_skip_counter。注意:仅对基于语句复制(SBR)有效;如果是基于行复制(RBR),这个变量无效,必须用 SET GLOBAL gtid_next 或注入空事务。
- 先停复制:
STOP SLAVE; - 确认当前是 SBR:
SELECT @@binlog_format;返回STATEMENT才能用下一行 - 跳过 1 条事件:
SET GLOBAL sql_slave_skip_counter = 1; - 重启:
START SLAVE; - 立刻检查:
SHOW SLAVE STATUS\G看Slave_SQL_Running是否为YES,以及Exec_Master_Log_Pos是否前进
⚠️ 风险:跳过可能导致主从数据不一致,尤其涉及 UPDATE 或 DELETE 时;跳过之后务必人工核对对应表的数据差异。
如何定位具体哪条 SQL 导致失败
靠 Last_SQL_Error 有时信息太模糊(比如只写 “Duplicate entry ‘x’ for key ‘PRIMARY’”),需要反查 relay log 对应位置的原始事件。
- 从
SHOW SLAVE STATUS\G中记下Relay_Master_Log_File和Exec_Master_Log_Pos(注意不是Read_Master_Log_Pos) - 用
mysqlbinlog解析 relay log 文件(路径见Relay_Log_File所在目录,文件名类似hostname-relay-bin.000002):mysqlbinlog --base64-output=DECODE-ROWS -v hostname-relay-bin.000002 | grep -A 10 -B 10 "exec_master_log_pos_value" - 更准的方式是用位置精确解析:
mysqlbinlog --base64-output=DECODE-ROWS -v --start-position=12345 hostname-relay-bin.000002(12345 替换为Exec_Master_Log_Pos) - 重点看
### UPDATE/### INSERT块,结合WHERE条件和SET值,还原出实际执行语句
别依赖 SHOW BINLOG EVENTS —— 它对 RBR 输出不友好,且不显示行变更细节。
GTID 模式下怎么修复 SQL 线程中断
开启 GTID 后,sql_slave_skip_counter 被禁用,必须用事务级跳过。核心思路是伪造一个空事务,让 GTID 集合往前挪一位。
- 停复制:
STOP SLAVE; - 查出下一个要执行的 GTID:
SHOW SLAVE STATUS\G中看Retrieved_Gtid_Set和Executed_Gtid_Set的差集,或直接看Auto_Position是否为1(表示启用了自动定位) - 设下一个 GTID(例如
aaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee:12345):SET GTID_NEXT='aaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee:12345'; - 执行空事务:
BEGIN; COMMIT; - 重置 GTID_NEXT 回自动模式:
SET GTID_NEXT='AUTOMATIC'; - 启动:
START SLAVE;
漏掉 SET GTID_NEXT 或顺序错会导致 ERROR 1840;伪造的 GTID 必须严格等于下一个待执行的,不能猜,否则可能跳过不止一条。
真正麻烦的不是操作步骤,而是判断“该不该跳”——有些错误(比如主键冲突)说明从库已有脏数据,强行跳过只会让不一致扩散。这时候得先清数据、再同步,而不是修线程。











