应先排查连接泄漏而非直接重启,90%的“too many connections”源于大量sleep连接堆积;通过show variables like 'max_connections'、show status like 'threads_connected'和show status like 'threads_running'可判断是否真满——若前者接近后者但threads_running很低,即为连接未释放所致。

能连上就别重启,先查清是连接泄漏还是配置太小——90% 的 Too many connections 都是 Sleep 连接堆出来的,不是真并发高。
怎么看当前连接是不是真满了?
用 root 走 socket 登录(mysql -uroot -p -S /var/lib/mysql/mysql.sock),执行这三条命令:
-
SHOW VARIABLES LIKE 'max_connections';—— 看上限,MySQL 5.7/8.0 默认是 151 -
SHOW STATUS LIKE 'Threads_connected';—— 看已建连接总数(含 Sleep) -
SHOW STATUS LIKE 'Threads_running';—— 看正在执行 SQL 的连接数
如果 Threads_connected 接近甚至等于 max_connections,但 Threads_running 很低(比如
怎么快速清理堆积的 Sleep 连接?
别直接 kill 所有 Sleep 进程,先过滤出可疑的:
- 查出空闲超 300 秒(5 分钟)的连接:
SELECT ID, USER, HOST, DB, COMMAND, TIME, STATE FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND = 'Sleep' AND TIME > 300; - 确认无关键事务后,批量 kill:
KILL 12345, 12346, ...;(ID 来自上一步结果) - 或者用脚本一键杀(慎用):
SELECT CONCAT('KILL ', ID, ';') FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND = 'Sleep' AND TIME > 300;,复制输出结果再执行
注意:KILL 不会丢数据,但会中断当前连接上的操作;如果应用没做重试,可能报错一次,但比服务全挂强。
为什么调大 max_connections 常常治标不治本?
临时设高只是把问题往后推,还可能引发新问题:
-
SET GLOBAL max_connections = 1000;生效快,但 MySQL 重启就失效 - 每个连接吃内存(约 256KB–2MB),盲目设到 2000+ 可能触发 OOM,尤其内存
- 真正该调的是
wait_timeout和interactive_timeout(默认 28800 秒=8 小时),建议缩到 300–900 秒(5–15 分钟) - 改完要写进
my.cnf的[mysqld]段落,否则重启丢失
改配置后必须重启 MySQL(或用 systemctl restart mysqld),光 reload 不生效。
应用层最容易被忽略的泄漏点
数据库连接不是“打开就完事”,漏掉关闭动作就会持续占坑:
- PHP/Python 脚本里没写
close()或没进finally块,异常一抛,连接就悬着 - Java 用 JDBC 没套
try-with-resources,或 Spring@Transactional嵌套过深导致连接未归还 - 连接池
max-active设得比 MySQL 的max_connections还高,多个服务一起压,瞬间打满 - 定时任务、后台脚本跑完不 close,每天累积几个 Sleep 连接,几周就爆
最稳妥的做法:所有获取连接的地方,确保对应有明确的释放逻辑,哪怕加个日志打点验证是否执行到 close。线上环境建议开慢查询日志 + 连接池监控,别等报错才看。











