最该盯住的三行是:1. Slave_IO_Running 和 Slave_SQL_Running 必须均为 Yes;2. Seconds_Behind_Master 非 NULL 且持续增大说明 SQL 线程卡住;3. Last_SQL_Error 直接显示冲突报错,如主键重复。

查 SHOW SLAVE STATUS 里最该盯住的三行
主从同步出问题,第一反应不是翻日志,而是先看 SHOW SLAVE STATUS\G 的输出——它比错误日志更直接、更实时。重点盯住这三行:
-
Slave_IO_Running和Slave_SQL_Running:必须都是Yes,任一为No就说明链路断了 -
Seconds_Behind_Master:非NULL且持续增大,大概率是 SQL 线程卡在某条语句上 -
Last_SQL_Error:最直白的报错信息,比如Duplicate entry '123' for key 'PRIMARY',直接暴露冲突点
注意:Seconds_Behind_Master 为 NULL 通常意味着 SQL 线程没在运行(比如刚 stop slave),不是“同步很快”。
错误日志里搜 Got fatal error 和 relay-log 相关路径
MySQL 错误日志(error.log)不是拿来通读的,而是带着关键词精准定位。主从异常时,优先 grep 这两类内容:
- 搜索
Got fatal error:这类日志往往出现在 IO 线程崩溃前后,常伴随Could not parse relay log event entry - 检查
relay-log路径是否可写:比如配置了relay_log = /data/mysql/relay-bin,但/data/mysql目录磁盘满或权限不对,IO 线程会静默失败,Last_IO_Error可能只显示Failed to open the relay log
别漏掉 log_error_verbosity = 3(MySQL 8.0.22+)这个配置,它能让错误日志包含更多上下文,比如具体是哪条 binlog event 触发失败。
用 mysqlbinlog 解析出问题的 relay log 文件
当 Last_SQL_Error 提示某条语句执行失败(比如主键冲突、字段类型不匹配),而你又不确定这条语句到底长什么样,就得靠 mysqlbinlog 拆解对应的 relay log:
- 先从
SHOW SLAVE STATUS里拿到Relay_Log_File和Exec_Master_Log_Pos - 执行
mysqlbinlog --base64-output=DECODE-ROWS -v /path/to/relay-bin.000001 | tail -n 50,快速查看末尾几十行事件 - 如果报错涉及行格式变更(如
ALTER TABLE ... ALGORITHM=INSTANT),旧版本 MySQL 可能无法解析新格式的 event,导致 SQL 线程停止
注意:mysqlbinlog 版本要和目标 MySQL 版本尽量一致;用低版本解析高版本生成的 binlog,可能直接报 unknown compression type 或跳过关键 event。
跳过错误前先确认是不是 SET GLOBAL sql_slave_skip_counter 还是 gtid_next
跳过错误不是万能解法,但真要用,得选对方式,否则可能让主从数据彻底不一致:
- 传统复制(非 GTID):用
SET GLOBAL sql_slave_skip_counter = 1,然后START SLAVE;但只跳过下一条 event,不能跳过一个事务 - GTID 复制:必须用
SET GTID_NEXT='xxx-xxx-xxx:nnn'; BEGIN; COMMIT;注入空事务,再重置GTID_NEXT;硬设sql_slave_skip_counter会报错Cannot use sql_slave_skip_counter when @@GLOBAL.GTID_MODE = ON - 跳过之后务必立刻验证:查几张关键表的
COUNT(*)和主库对比,别只看Seconds_Behind_Master变成 0 就以为万事大吉
真正难处理的是 DDL + DML 混合事务失败(比如 ALTER TABLE 后紧跟 INSERT),这种情况下跳过单条语句可能破坏表结构一致性,得人工补数据或重建从库。


















