必须先查innodb_trx定位真实事务再选命令:show processlist看不到事务级细节,90%长事务藏在command='sleep'但trx_state='running'的“假空闲”连接中;mysql 5.7应据状态选kill connection(持锁或sleep长事务)或kill query(仅中断慢语句)。

直接用 KILL 或 KILL QUERY 杀线程 ID,大概率杀错、杀晚、或锁不释放——必须先查 INNODB_TRX 定位真实事务,再按版本和状态选对命令。
为什么不能只看 SHOW PROCESSLIST?
它只反映连接层状态,完全看不到事务级细节:一个 Command = 'Sleep'、State = NULL、Time = 1800 的连接,可能正持着 EXCLUSIVE MDL 锁或上千行行锁,但 PROCESSLIST 里 INFO 为空、毫无提示。真正卡住的长事务,90% 都藏在这种“假空闲”连接里。
必须查 INFORMATION_SCHEMA.INNODB_TRX,重点盯三个字段:
-
TRX_STARTED:事务真实开始时间,用TIMESTAMPDIFF(SECOND, TRX_STARTED, NOW())算持续秒数,别信PROCESSLIST.TIME -
TRX_STATE = 'RUNNING':说明事务没提交也没回滚,还在活跃持有资源 -
TRX_MYSQL_THREAD_ID:这才是你要KILL的目标 ID,它和PROCESSLIST.ID不一定相等
MySQL 5.7 中该用 KILL QUERY 还是 KILL CONNECTION?
5.7 支持 KILL QUERY 和 KILL CONNECTION(等价于老式 KILL),但选哪个取决于连接当前行为:
- 如果线程
State是Locked、Waiting for table metadata lock或长时间Sleep且TRX_STATE = 'RUNNING'→ 用KILL CONNECTION <code>thread_id - 如果线程
State是Query且正在跑一个慢 SELECT/UPDATE,但应用还想复用连接 → 用KILL QUERY <code>thread_id - 严禁对等待方(
TRX_WAITING_TRX_ID IS NOT NULL)执行KILL CONNECTION:这会让持锁者继续跑,堵得更死
执行顺序必须是:先从 INNODB_TRX 找出 TRX_MYSQL_THREAD_ID → 再查 performance_schema.threads 确认 PROCESSLIST_USER 和 PROCESSLIST_INFO 留痕 → 最后发 KILL 命令。
KILL 后锁还没释放?不是命令失败,是回滚在后台跑
SHOW PROCESSLIST 显示状态为 Killed 是正常现象,不代表事务已结束。InnoDB 回滚耗时通常是正向操作的 3–5 倍:
- 几行 UPDATE:回滚一般
- 百万行 UPDATE 或大事务:可能卡在
Rolling back状态几分钟,期间锁仍被占用 - 务必再查
INNODB_TRX中该事务的TRX_OPERATION_STATE是否为rolling back,以及TRX_ROWS_MODIFIED估算剩余工作量
若发现 kill 后锁“一直不放”,优先确认是不是回滚本身太重,而不是命令没生效。
别写轮询脚本批量 KILL,用 pt-kill --print 先预演
手写 SELECT ... FROM INNODB_TRX + CONCAT('KILL ', ...) 脚本风险极高:
- 查完瞬间事务可能已提交,
KILL就变成误杀 - 拼接用户输入字段(如
USER)易引入 SQL 注入 - 没做连接重试、权限校验、状态二次确认
生产环境强烈推荐用 pt-kill,例如:
pt-kill --busy-time 60 --match-state Running --victims all --kill --print
加 --print 会只输出将要执行的 KILL 语句,不真执行,人工核对无误后再去掉该参数。它自动跳过 system_user、复制线程,并内置竞争规避逻辑。











