FLUSH TABLES 被 MDL 阻塞的根本原因是需等待所有表空闲,即无活跃事务持有 MDL_SHARED_READ 锁;若存在长事务或隐式事务,它将卡在 Waiting for table flush 状态。

FLUSH TABLES 为什么会被 MDL 阻塞
执行 FLUSH TABLES 时卡住,根本原因不是它自己要加锁,而是它必须等所有表“空闲”——即没有活跃事务正在访问这些表。一旦某张表被事务持有 MDL_SHARED_READ(比如一个长事务里执行了 SELECT),FLUSH TABLES 就会阻塞在那张表上,等待事务提交或回滚。
这和 FLUSH TABLES WITH READ LOCK(FTWRL)不同:FTWRL 是主动加全局读锁,而普通 FLUSH TABLES 只是“尝试关闭所有打开的表”,但它无法强制中断正在运行的语句。
- 常见现象:
SHOW PROCESSLIST中看到状态为Waiting for table flush - 本质是等待
MDL释放,不是等待行锁或 InnoDB 缓冲池刷盘 - 即使没显式开启事务,隐式事务(如自动提交关掉后的一条
SELECT)也会延长 MDL 持有时间
如何判断当前是否适合执行 FLUSH TABLES
别凭感觉执行,先查有没有人在“占着表不放”。核心是检查 performance_schema.metadata_locks 和活跃事务:
- 查哪些线程正持有 MDL 锁:
SELECT OBJECT_SCHEMA, OBJECT_NAME, LOCK_TYPE, LOCK_STATUS, OWNER_THREAD_ID FROM performance_schema.metadata_locks WHERE LOCK_STATUS = 'GRANTED' AND OBJECT_SCHEMA NOT IN ('mysql','sys','performance_schema'); - 查长事务(尤其没提交的):
SELECT trx_id, trx_started, trx_state, trx_mysql_thread_id FROM information_schema.innodb_trx ORDER BY trx_started LIMIT 5; - 结合
PROCESSLIST看线程状态:SELECT ID, USER, HOST, DB, COMMAND, TIME, STATE, INFO FROM information_schema.PROCESSLIST WHERE COMMAND != 'Sleep' AND TIME > 60;
如果发现某个线程 STATE 是 executing 或 Sending data,且 TIME 很大,大概率就是它拦住了 FLUSH TABLES。
安全执行 FLUSH TABLES 的实操步骤
目标不是“立刻执行”,而是“最小干扰、可控退出”。关键动作顺序不能错:
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 先确认无长事务:
KILL掉已知无关紧要的长时间空闲连接(如未提交事务的管理终端) - 临时降低并发压力:可短时暂停应用写入(如切到只读模式、限流),减少新 MDL 请求涌入
- 用带超时的命令执行:
SET SESSION lock_wait_timeout = 5; FLUSH TABLES;—— 超时失败比无限等待更可控 - 若仍卡住,不要反复重试,改用分表刷新:
FLUSH TABLES t1, t2, t3;隔离问题表,避免全库阻塞
注意:FLUSH TABLES 不会释放 MDL 锁本身,它只是等待已有锁释放;它也不会触发 DDL 等待队列的重新调度,所以别指望它“疏通”阻塞链。
为什么 FLUSH TABLES WITH READ LOCK 更危险
很多人想用 FTWRL 替代普通 FLUSH TABLES,结果引发更严重阻塞。原因在于 FTWRL 和 MDL 的互斥逻辑:
- FTWRL 必须获取所有表的
MDL_INTENTION_EXCLUSIVE,而这个请求会被任何已持有的MDL_SHARED_READ阻塞 - 一旦 FTWRL 卡住,后续所有新来的查询(包括
SELECT)都会排队等 FTWRL 完成,形成雪崩 - MySQL 8.0 后,FTWRL 还会阻塞
performance_schema的元数据更新,导致你连排查工具都失效 - 真正需要 FTWRL 的场景极少(如物理备份前的瞬时一致性),日常运维请绕开它
最常被忽略的一点:FLUSH TABLES 本身不修改数据,但它的阻塞效应会把原本分散的 MDL 等待集中暴露出来——你看到的不是新问题,而是旧问题终于浮出水面了。










