pt-kill默认仅打印不杀,必须显式加--kill或--kill-query才生效;需配--busy-time设阈值,且用户须有PROCESS+CONNECTION_ADMIN权限;应配合--ignore-和--match-精准过滤,避免误杀复制或监控线程,并通过--interval、--log和--victims all实现生产级稳定运行。

pt-kill 默认不杀任何查询,必须显式加 --kill 或 --kill-query
很多人跑完命令发现阻塞还在,根本原因就是漏了 --kill 或 --kill-query。它默认只打印匹配项(--print 模式),纯观察,不执行终止动作。
--kill 会断开整个连接(含后续复用可能);--kill-query 只中断当前 SQL,连接保持活跃——对有重试逻辑的应用更友好。
- 两者都必须配合
--busy-time N(单位秒),例如--busy-time 30表示查杀已执行超 30 秒的线程 - 若目标是锁阻塞场景,
--kill-query更稳妥:避免因断连导致应用重试放大压力 - 不加这两个参数,哪怕其他条件全对,也什么都不会发生
权限不足会导致“命令成功但无效果”
没有 PROCESS + CONNECTION_ADMIN(MySQL 8.0+)或 SUPER(5.7 及以前),pt-kill 就无法真正发送 KILL 指令——这是生产环境最常踩的坑。
- 不要用 root 直接跑;建专用账号,例如:
CREATE USER 'ptkiller'@'localhost' IDENTIFIED BY 'xxx'; - 授予权限:
GRANT PROCESS, CONNECTION_ADMIN ON *.* TO 'ptkiller'@'localhost'; - MySQL 8.0+ 若启用了角色模型,还需确认该用户被赋予对应角色,否则报错
Access denied; you need (at least one of) the CONNECTION_ADMIN privilege(s)
只靠 --busy-time 会误杀合法长事务,必须结合状态和锁信息过滤
迁移中的 INSERT SELECT、大 DDL、备份任务等,可能长时间处于 executing 状态,但并非阻塞源。单纯按时间阈值杀,容易中断关键任务。
真正引发锁阻塞的线程,典型特征是:State 为 Locked、Waiting for table metadata lock,或 Info 中含 FOR UPDATE、LOCK IN SHARE MODE 等显式锁语句。
- 优先用
--match-state="Locked|Waiting for table metadata lock"锁定可疑状态 - 补充
--match-info="FOR UPDATE|LOCK IN SHARE MODE|SELECT ... FROM .* WHERE .* FOR UPDATE"精准捕获锁相关 SQL - 排除已知安全长耗时操作:
--ignore-command="Binlog Dump,Change master,Start slave,pt-online-schema-change" - 慎用
--victims=oldest:最老连接未必是锁持有者,--victims=all更可控,但需配合--limit 1防止一次杀太多
生产环境必须加 --log 和合理 --interval,否则等于裸奔
没日志,就等于没监控——你不知道谁被杀了、为什么杀、SQL 是什么。而轮询太密,会加重主库压力;太疏,又可能让阻塞持续几十秒。
- 务必加
--log /var/log/pt-kill.log:所有 kill 记录、线程 ID、SQL 片段、时间戳都会落盘,故障回溯唯一依据 -
--interval 5是较平衡的选择;低于 3 秒易引发 CPU 毛刺,高于 15 秒可能导致阻塞窗口过长 - 避免用
--daemonize启动后就不管:应配合 systemd 或 supervisor 管理进程生命周期,并设置--run-time限制单次运行时长(如 3600),便于滚动重启与配置更新 - 上线前先用
--print跑 10 分钟,确认匹配结果符合预期再启用--kill-query
真实锁阻塞往往藏在 Sleep 线程背后——那些未提交事务的空闲连接,才是 MDL 锁的真正持有者。只盯着 “正在执行”的 Query,可能永远抓不到元凶。


















