必须开启binlog_rows_query_log_events=ON才能在ROW模式下看到原始SQL,否则仅能通过行事件反推操作;该参数需重启生效且仅对新binlog有效,排查时应结合end_log_pos定位事件并验证主从position或GTID一致性。

直接看 end_log_pos 对应的事件,再结合 binlog_rows_query_log_events=ON 记录的原始 SQL,才能确认哪条语句导致主从不一致——否则你只能看到“某行丢了”,却不知道谁删的、为什么删。
查错时先确认 binlog 是否记录了原始 SQL
很多线上环境只开了 binlog_format=ROW,但没开 binlog_rows_query_log_events=ON。结果就是 mysqlbinlog -v 输出里只有 Update_rows 或 Delete_rows 事件,看不到 # Query 行。这意味着你无法知道触发变更的应用逻辑或 SQL 语句。
- 执行
SELECT @@binlog_rows_query_log_events;,返回1才表示已启用 - 若为
0,需在my.cnf中添加binlog_rows_query_log_events=ON并重启 MySQL(注意:该参数不可动态修改) - 即使开了这个参数,也只对新写入的 binlog 生效;旧文件仍无原始 SQL,别白费力气去解析
定位报错位点对应的 SQL 语句
主从同步失败时错误日志里通常带 end_log_pos 和 binlog 文件名,比如:the event’s master log mysql-bin.000101, end_log_pos 711518695。这个位置就是出问题的事件结尾,要往前找最近的 Query 或 Table_map 事件。
- 用命令提取该位置附近内容:
mysqlbinlog --no-defaults --base64-output=decode-rows -v --start-position=711518600 --stop-position=711518700 /var/lib/mysql/mysql-bin.000101 -
--start-position要略小于报错位置(建议减 100),避免跳过事件头;--stop-position略大于即可 - 重点看输出中以
# Query开头的行(有原始 SQL)和紧随其后的Table_map+Update_rows/Delete_rows块,它们属于同一事务 - 如果没看到
# Query行,说明该 binlog 文件未开启binlog_rows_query_log_events,只能靠表名、主键值反推业务上下文
过滤特定库表或操作类型提升排查效率
生产环境 binlog 文件动辄几百 MB,全量解析太慢。用管道配合 grep 可快速聚焦目标:
- 只看某个库的变更:
mysqlbinlog --no-defaults -v mysql-bin.000101 | grep -A 10 -B 2 "database_name" - 找 DELETE 操作:
mysqlbinlog --no-defaults -v mysql-bin.000101 | grep -A 5 -B 1 "Delete_rows" - 匹配某张表的更新:
mysqlbinlog --no-defaults -v mysql-bin.000101 | grep -A 8 -B 2 "\`schema_name\`.\`table_name\`" - 注意:加
--base64-output=decode-rows后,Delete_rows这类关键词才可见;不加则只显示 base64 编码块,grep 无效
对比主从数据差异时别忽略 GTID 和 position 的一致性
单纯看 binlog 内容还不够,得确认从库当前同步到的位置是否和主库一致。否则你分析的可能是从库早已跳过的事件。
- 在主库查:
SHOW MASTER STATUS;,记下File和Position(或Executed_Gtid_Set) - 在从库查:
SHOW SLAVE STATUS\G,重点关注Relay_Master_Log_File和Exec_Master_Log_Pos(非Read_Master_Log_Pos) - 若两者 position 不同,说明从库落后;此时解析主库 binlog 时,必须限定
--start-position≥ 从库已执行位置,否则会漏掉中间变更 - GTID 模式下更简单:
SELECT * FROM performance_schema.replication_applier_status_by_worker;可直接看到每个 worker 卡在哪条事务
真正难的不是解析命令怎么写,而是当 binlog_rows_query_log_events 关着、又没监控 SQL 审计日志时,你得靠 WHERE 条件里的主键值、时间戳字段、甚至业务表字段含义去倒推那条“坏 SQL”长什么样——这时候,数据库表设计是否带操作人、时间、来源标识,就决定了你能不能在 1 小时内定位,还是得花一整天猜。


















