waiting for table flush 是因表被长查询、大事务或显式锁占用导致 flush 无法关闭表;需通过 show processlist 定位高 time 非 sleep 线程并 kill,而非直接杀 flush 线程。

查清谁在阻塞 flush 流程
Waiting for table flush 不是锁等待,而是“想关表但关不掉”——通常是因为某张表正被长查询、大事务或显式锁(如 LOCK TABLES)长期持有,导致后续的 FLUSH TABLES 或 DDL 操作卡住。此时所有新来的查询(哪怕只是 SELECT)只要涉及该表,就会排队等这个 flush 完成。
关键动作是定位「最早那个没结束的线程」:
- 运行
SHOW PROCESSLIST,找State非Sleep且Time值明显偏高(比如 >300 秒)的线程,尤其是状态为Sending data、Copying to tmp table、User sleep或Locked的 - 重点看
Info列是否含SELECT全表扫描、JOIN多表未走索引、或带SLEEP()的测试语句 - 如果看到
FLUSH TABLES或FLUSH TABLES WITH READ LOCK自身处于Waiting for table flush,说明它就是被堵住的源头,不是原因
确认是否由备份或运维操作触发
很多线上 Waiting for table flush 是 mysqldump、innobackupex 或自定义备份脚本引发的,尤其当它们没加 --single-transaction 或误用了 --lock-all-tables。
检查方法:
- 查慢日志或 general log 中是否有
FLUSH TABLES、FLUSH TABLES t1、ANALYZE TABLE、OPTIMIZE TABLE等语句,时间点是否与阻塞开始吻合 - RDS 用户可直接查审计日志或控制台操作记录;自建库可 grep
mysql-error.log或general_log_file中的flush - 注意:即使
FLUSH命令已超时退出或被 Ctrl+C 中断,其对表的“关闭等待”状态仍会残留,直到原持有者释放表
别忽略表缓存和 open_files_limit 的硬限制
table_open_cache 过小会让 MySQL 频繁打开/关闭表文件,而大查询又拖长单次打开周期,最终让 flush 队列积压。这不是逻辑阻塞,而是资源周转瓶颈。
验证与调整:
- 执行
SHOW GLOBAL STATUS LIKE 'Opened_tables',若每秒增长 >50,说明缓存严重不足 - 对比
SHOW VARIABLES LIKE 'table_open_cache'和系统级open_files_limit(可用cat /proc/$(pidof mysqld)/limits | grep "Max open files"查),前者不能超过后者 - 调大需同步改
open_files_limit(systemd 下改LimitNOFILE),否则 MySQL 启动时会静默降级到默认值
KILL 的顺序不能反:先杀慢查询,再等 flush 自行恢复
常见错误是直接 KILL 那个显示 FLUSH TABLES 的线程——这没用。真正卡住的是它想关但关不掉的那张表的持有者。
正确做法:
- 从
SHOW PROCESSLIST找出Time最大的非 Sleep 查询线程(比如 Id=9140),KILL 9140 - 等几秒,观察其他线程的
State是否从Waiting for table flush变回executing或消失 - 如果还有残留,再查
performance_schema.metadata_locks(需提前开启对应 instrument),确认是否有SHARED_READ或EXCLUSIVE锁未释放
最易被忽略的一点:MyISAM 表在并发读场景下每个线程都独占一个表实例,Waiting for table flush 出现频率和持续时间会远高于 InnoDB——如果你还在用 MyISAM,这个问题几乎必然发生,且无法靠调参根治。











