答案是连接泄漏而非max_connections过小——90%的“too many connections”源于应用未释放连接或连接池配置错误,需通过threads_connected与threads_running对比确认堆积,排查ulimit、systemd限制及set persist持久化配置,并优先优化应用层连接池参数。

不是max_connections设小了,是连接堆在那儿不释放——90% 的 Too many connections 报错,根源在应用层没关连接或连接池配错。
怎么确认是不是真连满了
别急着改配置。哪怕应用连不上,用 root 通过本地 socket 还能进(MySQL 预留一个紧急连接位):
-
SHOW VARIABLES LIKE 'max_connections';—— 看上限,默认 151 -
SHOW STATUS LIKE 'Threads_connected';—— 当前已建连数 -
SHOW STATUS LIKE 'Threads_running';—— 正在干活的线程数
如果 Threads_connected 接近 max_connections,但 Threads_running 极低(比如 500 连接里只有 2 个在跑),说明全是 Sleep 状态,基本就是泄漏或空闲连接堆积。
为什么 SET GLOBAL max_connections 经常不生效
执行 SET GLOBAL max_connections = 1000; 后查变量还是旧值?卡点不在 MySQL 本身,而在三道硬限制:
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
- 运行
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 参数更关键
多数线上事故根子在应用侧。比如 Druid 或 HikariCP 常见错配:
-
max-active(Druid)或maximumPoolSize(HikariCP)设得比max_connections还高,多个服务一起压就爆 -
wait_timeout(MySQL)设为 300 秒,但连接池的idleTimeout设成 600 秒,连接永远归还不回去 - HikariCP 的
connection-timeout默认 30 秒,网络抖动易堆积;建议调到 10–15 秒,并开leak-detection-threshold - PHP 脚本发生
fatal error时,mysqlnd不会自动归还连接,必须显式mysqli_close()
kill Sleep 连接只是应急,不是解法
SHOW PROCESSLIST; 里看到一堆 Sleep 连接,KILL 掉能抢出几个名额,但几小时后又满——因为泄漏还在继续。
重点查 USER 和 HOST:SELECT USER, HOST, COUNT(*) FROM information_schema.PROCESSLIST GROUP BY USER, HOST; 定位异常 IP 或账号。真正要盯的是 Max_used_connections:长期 >90% 就该预警,不是等报错才查。
连接池最大数应 ≤ max_connections 的 70%,留余量给后台线程和管理员连接;每调高 100 个连接,内存至少多占 256MB,盲目设高可能触发 OOM。










