跳过GTID复制错误必须先准确获取卡住的GTID:查SHOW SLAVE STATUS\G中的Last_SQL_Error、Retrieved_Gtid_Set与Executed_Gtid_Set差集,并确保STOP SLAVE后设slave_parallel_workers=0,再执行SET GTID_NEXT='xxx:nnn'; BEGIN; COMMIT;,最后验证Seconds_Behind_Master=0且GTID差集缩小。

确认报错事务的GTID值
跳过前必须准确拿到那个卡住复制的GTID,不能靠猜。直接查 SHOW SLAVE STATUS\G,重点看三处:Last_SQL_Error 里通常带完整 GTID(如 '6c9da32f-0513-11e4-a949-00e04c8a7573:1');Retrieved_Gtid_Set 和 Executed_Gtid_Set 的差集也能反推;如果 SQL 线程已停,Slave_SQL_Running_State 是 Waiting for dependent transaction to commit 这类状态,说明卡点明确。
别跳进 performance_schema.replication_applier_status_by_coordinator 查——它只反映 coordinator 线程视角,而 GTID 卡点往往在 worker 线程,容易误判。真要交叉验证,用 SELECT * FROM performance_schema.replication_applier_status_by_worker WHERE LAST_ERROR_NUMBER != 0; 更准。
STOP SLAVE 后必须关掉并行复制
slave_parallel_workers 必须为 0,否则 SET GTID_NEXT 行为不可控:多线程下你设的 GTID 可能被另一个 worker 拦截或忽略,导致空事务没打上目标 GTID,后续 START SLAVE 直接报 ERROR 1840 (HY000) 或卡死在 Waiting for master to send event。
操作顺序不能乱:
- 先
STOP SLAVE; - 再
SET GLOBAL slave_parallel_workers = 0;(改完立刻SELECT @@slave_parallel_workers;确认) - 最后才执行
SET GTID_NEXT = 'xxx:nnn';
改完别急着开复制——有些版本在 slave_parallel_workers > 0 时设了 GTID_NEXT,会静默失效,且不报错。
BEGIN; COMMIT; 不是可选,是强制步骤
SET GTID_NEXT = 'xxx:nnn' 本身不产生事务,只是“预约”下一个事务的 GTID。你不手动提交一个事务,MySQL 就永远等不到那个 GTID 对应的事务落地,复制状态机不会推进。
常见错误写法:
-
SET GTID_NEXT = 'xxx:nnn'; COMMIT;—— 错。没有BEGIN,COMMIT无效,MySQL 会报ERROR 1632 (HY000): Cannot execute statement in a READ ONLY transaction(尤其在read_only=ON从库上) -
CREATE TABLE t1(id INT); DROP TABLE t1;—— 不推荐。DDL 在部分 MySQL 版本(如 Percona 5.7.14)中对 GTID 处理有边界问题,可能触发mysql.gtid_executed表重建异常
正确且最简写法只有:BEGIN; COMMIT;。执行后立刻 SELECT @@GTID_NEXT;,确认它还是你设的值(不是自动变回 AUTOMATIC),避免误连了其他会话。
注入后 Executed_Gtid_Set 不变?这是正常现象
注入空事务后,SHOW SLAVE STATUS\G 里的 Executed_Gtid_Set 看起来没更新,不代表失败。这是因为该字段只记录 relay log 中“真正重放”的事务,手工注入的事务属于“外部写入”,不走复制状态机流程。
验证是否成功,看三处:
-
Seconds_Behind_Master: 0且Slave_SQL_Running: Yes -
Retrieved_Gtid_Set和Executed_Gtid_Set的差集缩小了(比如原来差xxx:1,现在差xxx:2) - 执行
SELECT GTID_SUBTRACT('xxx:1-5', 'xxx:1');,返回xxx:2-5就说明xxx:1已被纳入已执行集合(即使没显式出现在Executed_Gtid_Set字符串里)
最容易被忽略的是:跳过之后,别立刻在从库上做任何 DML。因为刚注入的 GTID 并未对应真实数据变更,如果紧接着又执行同表操作,可能掩盖底层数据不一致,等下次主库发来冲突语句才暴露——那时就晚了。


















