应先用show full processlist识别真正持有锁的线程,再执行kill connection id终止;避免仅按time排序误杀等待者,需结合state、command和完整sql判断阻塞源头。

能直接 kill,但必须先准确识别出真正阻塞别人的那个线程,而不是只看 time 值大的。单纯按 time 排序杀掉耗时最长的 SQL,经常误杀无辜——它可能只是在等锁,自己没在执行,却把真正持有锁的源头漏掉了。
如何用 show processlist 找到真凶,不是替罪羊
阻塞链里,通常有「等待者」和「持有者」两类线程。只查 show processlist 默认输出,容易只看到一堆 State: Waiting for table metadata lock 或 Waiting for lock 的等待者,却找不到谁在 hold lock。
- 必须加
FULL:运行show full processlist,否则Info列会被截断,看不到完整 SQL,无法判断是否是 DDL、大事务或隐式锁操作 - 重点看
State列:出现Locked、Waiting for table metadata lock、Waiting for row lock的线程,大概率是等待者;而State: Sending data或updating且Time持续上涨的,更可能是持有锁正在执行的源头 - 结合
Command列:Command: Query表示正在执行 SQL;Command: Sleep但Time很大,说明事务没提交,锁还挂着——这种最危险,常被忽略 - 别只盯
information_schema.processlist:它的TIME是线程空闲/执行总秒数,不区分状态;而performance_schema.threads+performance_schema.data_locks(MySQL 8.0+)才能看到谁持有什么锁,但日常应急还是show full processlist最快
kill 命令的两种写法,效果完全不同
KILL 不是只有 KILL 123 一种用法。用错类型,可能什么都没终止,或者中断了不该中断的操作。
-
KILL 123(即KILL CONNECTION 123):强制断开客户端连接,会回滚当前事务,释放所有锁。这是最常用、最安全的杀法 -
KILL QUERY 123:只终止当前正在执行的语句,但连接保持,事务不回滚。如果该线程处于事务中且已修改数据,KILL QUERY后它可能立刻重试原 SQL 或卡在下一行,锁依然存在 - 不要用
KILL -9或操作系统级kill -9:MySQL 进程本身不能这么杀,会导致实例崩溃或数据不一致 - 权限要求:执行
KILL需要有SUPER或CONNECTION_ADMIN权限(MySQL 8.0.12+),普通应用账号默认没有
批量杀慢查询前,务必加过滤条件
线上环境一执行 SELECT ID FROM information_schema.processlist WHERE TIME > 60 就全量杀,极大概率引发雪崩。慢 ≠ 该杀,更不等于可以一起杀。
- 加
COMMAND = 'Query':排除Sleep线程,避免误杀长事务未提交的连接(它们Time大但未必在“执行”) - 加
INFO IS NOT NULL:过滤掉空Info的线程(比如某些监控探活连接),防止KILL报错Unknown thread id - 慎用正则匹配:如
INFO LIKE '%DELETE%'或INFO REGEXP '^(INSERT|UPDATE)',注意大小写和空格,SHOW FULL PROCESSLIST中的 SQL 是原始输入,可能含换行或注释 - 生产建议:先用
SELECT CONCAT('KILL ',ID,';') FROM ...生成 kill 语句,人工 review 后再执行;或用pt-kill工具替代,它支持--match-info和--ignore-command等精细控制
真正难的不是执行 KILL,而是从几十上百个线程里,在 30 秒内分辨出哪个是锁源头、哪个是连锁等待、哪个只是刚连上来还没干活的假慢。多看几遍 show full processlist 输出,比背命令重要得多;而每次 KILL 前确认 State 和 Info 内容,比记住语法关键得多。











