mysql连接池问题根源多为应用未释放连接或配置错误,需通过show processlist和threads_connected等指标定位sleep连接,并确保idletimeout严格小于wait_timeout以避免假泄漏。

这不是连接数真不够,而是旧连接“赖着不走”——90% 的 Too many connections 错误,根源在应用没关连接、连接池配错,或 wait_timeout 设得太大。
怎么确认是不是真连满了
别急着改配置。MySQL 给 root 留了一个紧急通道(max_connections + 1),只要还能本地 socket 登录,就能查清现状:
-
SHOW VARIABLES LIKE 'max_connections';—— 看上限,默认 151 -
SHOW STATUS LIKE 'Threads_connected';—— 当前已建连数 -
SHOW STATUS LIKE 'Threads_running';—— 正在干活的线程数
如果 Threads_connected 接近上限,但 Threads_running 只有 1–3 个,说明全是 Sleep 状态,基本就是泄漏或空闲堆积。
为什么 SET GLOBAL max_connections 经常不生效
执行了 SET GLOBAL max_connections = 1000; 却查不到新值?问题不在 MySQL,而在三道硬限制:
- 运行
ulimit -n,若返回 1024,而你想设 2000,MySQL 启动时会自动向下取整 - systemd 管理的服务必须在
/usr/lib/systemd/system/mysqld.service的[Service]段加:LimitNOFILE=65536和LimitNPROC=65536,再执行systemctl --system daemon-reload && systemctl restart mysqld - MySQL 8.0.22+ 支持
SET PERSIST max_connections = 1000;,它写入mysqld-auto.cnf,优先级高于my.cnf—— 若已用此方式,改配置文件也不覆盖
连接池参数比 MySQL 配置更关键
多数线上爆满事故,根子在应用侧。比如 HikariCP 或 Druid 常见错配:
-
maximumPoolSize(HikariCP)或maxActive(Druid)设得比max_connections还高,多个服务一起压就直接打满 -
wait_timeout设为 300 秒,但连接池的idleTimeout设成 600 秒 → 连接永远归还不回去 - HikariCP 的
connection-timeout默认 30 秒,网络抖动易堆积;建议调到 10–15 秒,并开启leak-detection-threshold - PHP 脚本发生
fatal error时,mysqlnd不会自动归还连接,必须显式调用mysqli_close()
kill Sleep 连接只是应急,不是解法
SHOW PROCESSLIST; 里看到一堆 Sleep 连接,KILL 掉能抢出几个名额,但几小时后又满——因为泄漏还在继续。
重点查来源:SELECT USER, HOST, COUNT(*) FROM information_schema.PROCESSLIST GROUP BY USER, HOST; 定位异常 IP 或账号。真正要盯的是 Time 列持续增长的连接,尤其是来自同一 HOST 的几十条同名连接——这几乎 100% 是代码里漏了 close() 或事务没提交。
最易被忽略的一点:连接池的 idleTimeout 必须严格小于 MySQL 的 wait_timeout,否则连接被 MySQL 主动断开后,池子还当它活着,下次复用就报错,形成“假泄漏”。











