MySQL中的“僵尸进程”实为长期Sleep且未断开的空闲连接,Command='Sleep'、Time超阈值(如>3600秒)、Info为空,占用连接资源但非OS级Zombie;需过滤User/Host/Time精准识别,避免误杀健康连接池连接,根治应调优wait_timeout等参数并检查应用层连接释放逻辑。

什么是MySQL里的“僵尸进程”?别被名字骗了
MySQL里没有真正意义上的操作系统级僵尸进程(defunct状态那种),所谓“僵尸进程”其实是运维/开发人员对长期处于 Sleep 状态、又不主动断开的空闲连接的俗称。它们不执行SQL,但占着连接数、内存和线程资源,容易触发 Too many connections 错误。
关键点在于:这些进程在 information_schema.PROCESSLIST 里显示 Command = 'Sleep',Time 值很大(比如几小时甚至几天),Info 为空——不是卡死,是“赖着不走”。
- 不是所有
Sleep进程都要杀:应用连接池维持的健康长连接也表现为Sleep,盲目清理会导致应用重连风暴 -
KILL操作针对的是连接(connection),不是单个查询;KILL QUERY只终止当前语句,对Sleep进程无效 - MySQL 8.0+ 中,
performance_schema.threads的PROCESSLIST_TIME比information_schema.PROCESSLIST.TIME更准,尤其在连接复用场景下
怎么精准筛出该杀的 Sleep 连接?
直接执行 SHOW PROCESSLIST 看一眼不够,得加条件过滤。重点看三个字段:User(谁连的)、Host(从哪来)、Time(挂了多久)。
推荐这条查询(适配 MySQL 5.7+):
SELECT ID, USER, HOST, DB, COMMAND, TIME, STATE, INFO
FROM information_schema.PROCESSLIST
WHERE COMMAND = 'Sleep'
AND TIME > 3600 -- 超过1小时的才纳入视野
AND USER NOT IN ('system_user', 'mysql.sys') -- 排除系统账号
AND HOST NOT LIKE '127.0.0.1%' -- 可选:排除本地管理连接
ORDER BY TIME DESC;-
TIME > 3600是底线,设太低会误伤正常连接池;生产环境可调到7200(2小时)甚至更高 - 如果发现大量来自同一
HOST的长时间Sleep,大概率是应用没正确 close() 连接,要查代码或连接池配置 -
INFO为空是必要特征;若非空,说明它正在执行语句,不属于“僵尸”,应归入慢查询排查范畴
批量终止时,为什么不能直接用 KILL + SELECT CONCAT?
很多人抄网上的 SELECT CONCAT('KILL ',id,';') ... INTO OUTFILE 脚本,但在实际生产中容易翻车:
-
INTO OUTFILE要求 MySQL 有写入目标路径的权限,且该路径必须在数据库服务器本地——容器或云托管实例往往不满足 - 生成的 SQL 文件若含特殊字符(如单引号嵌套),
SOURCE执行会报错:ERROR 1064 (42000) - 一次性
KILL太多连接,可能触发应用侧连接雪崩,下游服务瞬间收一堆Connection refused
更稳妥的做法是分批 + 带确认:
-- 先看要杀哪些(同上,加 LIMIT 控制范围) SELECT ID FROM information_schema.PROCESSLIST WHERE COMMAND = 'Sleep' AND TIME > 7200 LIMIT 10; <p>-- 确认无误后,逐条执行(或写简单 shell 循环) KILL 1234; KILL 5678;
或者用客户端工具(如 MySQL Shell)配合脚本逻辑控制节奏,避免冲击。
真正要根治,得从连接生命周期下手
杀进程只是止痛,不是治病。反复出现“僵尸”,说明连接没被正确释放:
- 检查应用层:是否用了连接池?最大空闲时间(
maxIdleTime或idleTimeout)是否设置合理?有没有漏掉close()调用? - 检查 MySQL 配置:
wait_timeout(默认 28800 秒=8小时)和interactive_timeout控制空闲连接超时,可酌情调低(如设为 3600) - 注意:改完配置需
SET GLOBAL wait_timeout = 3600;生效,且只影响新连接;已有连接仍按旧值计时 - 某些 ORM(如 Django 的
CONN_MAX_AGE)或框架(Spring Boot 的spring.datasource.hikari.idle-timeout)也有对应参数,优先调这里,比调 MySQL 更安全
最易被忽略的一点:MySQL 的 wait_timeout 对交互式连接(比如你用 mysql 客户端连的)生效的是 interactive_timeout,两者独立——调错一个,另一类连接照样“赖着”。


















