应调小wait_timeout和interactive_timeout(如设为60),及时释放空闲Sleep连接;优先优化应用层连接复用与正确关闭,而非盲目增大max_connections。

直接结论:别先动 max_connections,重点调小 wait_timeout 和 interactive_timeout,并确认应用是否漏关连接。
为什么大量 Sleep 连接会让 MySQL 响应变慢
MySQL 每个连接独占一个线程和内存(约 256KB),大量空闲的 Sleep 连接不释放,会快速耗尽 max_connections,新请求只能排队或被拒绝。这不是“并发高”,而是“连接没归还”。show processlist 看到几百个 Sleep,但 SELECT * FROM information_schema.PROCESSLIST WHERE COMMAND != 'Sleep' 只有十几条活跃查询,就是典型症状。
- Linux 默认
ulimit -n是 1024,若盲目把max_connections设为 2000,MySQL 启动会报Can't create thread (errno: 24) -
mysql_pconnect()在 PHP-FPM 下极易堆积Sleep连接,因为子进程退出时不销毁物理连接 - Java 应用常见漏写
connection.close()或ResultSet.close(),连接池以为连接已归还,实际还在 MySQL 里挂着
必须改的三个配置项及其取值逻辑
这三个参数共同控制空闲连接生命周期,调小才能“快进快出”:
-
wait_timeout:非交互式连接(如应用连接池创建的)空闲超时,默认 28800 秒(8 小时)→ 建议设为60~300(1~5 分钟) -
interactive_timeout:交互式连接(如 mysql 命令行)空闲超时,默认也是 28800 → 同样建议设为60~300,避免误操作后连接长期滞留 -
max_connections:不是越大越好。先查历史峰值:SHOW STATUS LIKE 'Threads_connected';,再设为该值的 1.5~2 倍。超过 1000 后每增 1 连接,MySQL 多占约 256KB 内存
修改方式(需重启或动态生效):
SET GLOBAL wait_timeout = 60; SET GLOBAL interactive_timeout = 60;
永久生效则在 my.cnf 的 [mysqld] 下添加:
wait_timeout = 60 interactive_timeout = 60 max_connections = 500
应用层不配合,调参全是白忙
配置只是兜底,真正要靠应用代码收口:
- PHP 不要用
mysql_pconnect(),改用 PDO + 连接池,并确保finally块中调用$pdo = null或显式close() - Java 使用 HikariCP 时,
maximumPoolSize别设超过 20~30;务必开启connection-timeout=3000,防止单个卡死连接拖垮整个池 - 所有数据库访问必须显式关闭资源:Python 的
with conn、Java 的try-with-resources、Go 的defer rows.Close() - 检查 ORM 是否自动启用长连接或未配置连接回收策略(如 MyBatis 的
dataSource配置)
临时清理与验证方法
配置生效前,先手动清理积压的“僵尸连接”:
- 查出空闲太久的连接:
SELECT ID, USER, HOST, DB, COMMAND, TIME, STATE FROM information_schema.PROCESSLIST WHERE COMMAND = 'Sleep' AND TIME > 300; - 批量 KILL(谨慎执行):
KILL 123, 456, 789;(ID 来自上一步) - 验证效果:持续观察
SHOW STATUS LIKE 'Threads_connected';峰值是否回落,且不再持续攀升
最易被忽略的一点:wait_timeout 和 interactive_timeout 必须同时调小。只改一个,另一类连接仍会堆积,问题照旧。


















