Slave SQL线程卡在“Waiting for table metadata lock”是由于从库上DDL被阻塞,导致后续relay log无法执行;需查并kill持有MDL锁的会话,禁用sql_slave_skip_counter(GTID模式下),优先用pt-online-schema-change避免锁表。

Slave SQL线程卡在“Waiting for table metadata lock”怎么办
直接结论:这不是主从同步本身的问题,而是从库上某条 DDL(比如 ALTER TABLE)被阻塞,导致后续所有 relay log 里的语句无法执行,SQL 线程停在元数据锁等待上。
典型现象是 SHOW SLAVE STATUS\G 中 Seconds_Behind_Master 持续增长,Slave_SQL_Running_State 显示 Waiting for table metadata lock,且 Exec_Master_Log_Pos 不再推进。
- 先查阻塞源头:
SELECT * FROM performance_schema.metadata_locks WHERE OBJECT_SCHEMA = 'your_db' AND OBJECT_NAME = 'your_table'; - 再看谁在持有锁:
SELECT * FROM performance_schema.threads t JOIN performance_schema.metadata_locks ml ON t.THREAD_ID = ml.OWNER_THREAD_ID WHERE ml.OBJECT_SCHEMA = 'your_db' AND ml.OBJECT_NAME = 'your_table'; - 重点检查
PROCESSLIST中状态为Waiting for table metadata lock或长时间Running的会话,尤其是未提交的事务、长事务、或正在执行 DDL 的连接
为什么从库执行 DDL 容易引发锁冲突
MySQL 5.6+ 默认启用 slave_parallel_workers > 0 后,DDL 语句会被强制降级为单线程串行执行(即使其他 DML 并行),且 DDL 在从库执行时仍需获取全表 MDL 写锁——而此时如果主库刚发来一批并发 DML,它们在从库回放时可能正持有该表的 MDL 读锁,造成死锁式等待。
- DDL 在从库不是“原子跳过”,它必须等前面所有 relay log 里的语句执行完才能开始
- 从库没有主库的写负载压力,但锁粒度和行为完全一致;一个未提交的
SELECT ... FOR UPDATE就足以阻塞后续 DDL -
innodb_lock_wait_timeout对 MDL 锁无效,所以不会超时自动释放,只能人工干预
快速恢复 + 避免复发的操作清单
别急着 STOP SLAVE; START SLAVE; —— 这只会重试,不解决锁源。
- 确认阻塞会话 ID(从
performance_schema.threads查到的THREAD_ID),执行KILL [thread_id]终止持有锁的连接(注意:不要 kill SQL thread 自身) - 若阻塞来自长事务,优先
COMMIT或ROLLBACK对应事务;可通过information_schema.INNODB_TRX找出TRX_STATE = 'RUNNING'且TRX_STARTED很早的记录 - 预防措施:所有 DDL 必须在业务低峰期执行,并确保主库执行前,从库已无活跃事务访问目标表(可临时
SET GLOBAL innodb_lock_wait_timeout = 10;缩短等待容忍度,但仅作辅助判断) - 长期建议:将 DDL 操作统一走
pt-online-schema-change,它在从库也能安全执行,避免锁表
特别注意:GTID 模式下不能简单跳过事件
如果你启用了 gtid_mode = ON,千万不要用 SET GLOBAL sql_slave_skip_counter = 1 跳过当前事件——这会导致 GTID 集合不一致,后续同步直接报错 The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing GTIDs that the slave requires.
真正安全的做法只有两个:KILL 掉阻塞源,或用 STOP SLAVE; RESET SLAVE ALL; + 重新配置复制(代价高,仅限极端情况)。
最常被忽略的是:误以为“从库只读就没事”,其实只读只是禁止写入,不阻止本地连接发起 DDL 或长查询——这类操作照样抢锁、照样卡死 SQL 线程。


















