90%的“Too many connections”源于应用未关闭连接或连接池配置失当;应先执行SHOW VARIABLES LIKE 'max_connections'、SHOW STATUS LIKE 'Threads_connected'和SHOW STATUS LIKE 'Max_used_connections'确认是否真连满,再排查Sleep连接及超时设置。

直接改 max_connections 只能临时顶住,90% 的真实原因是应用没关连接,或连接池配置失当——先别动配置,登录进去看谁在占着不放。
怎么快速确认是不是真连满了
用管理员账号登录后立刻执行:
-
SHOW VARIABLES LIKE 'max_connections';看上限是多少(默认常是 151) -
SHOW STATUS LIKE 'Threads_connected';看当前连了多少个 -
SHOW STATUS LIKE 'Max_used_connections';看历史峰值,如果长期接近上限,说明不是瞬时高峰,而是泄漏或配置不合理
如果 Threads_connected 已经 ≥ max_connections − 1,新连接就会被拒;但注意:MySQL 允许 max_connections + 1 个连接,多出那 1 个是留给有 SUPER 权限的管理员的——所以你还能登进去,就是靠它。
为什么 SET GLOBAL max_connections = 500 有时不生效
常见假象:命令执行成功,但查 SHOW VARIABLES LIKE 'max_connections' 还是旧值。根本原因通常是:
- 操作系统级文件描述符限制太低:
ulimit -n返回值(比如 1024)小于你想设的max_connections(比如 2000),MySQL 启动时会自动向下取整 - 配置写错了段落:必须在
[mysqld]段里写max_connections = 500,写在[client]或全局位置无效 - 多个配置文件冲突:MySQL 只加载一个主配置文件(可用
mysqld --help --verbose | grep "Default options"确认路径),后加载的覆盖前一个 - MySQL 8.0.22+ 用了
SET PERSIST:它会把值写进mysqld-auto.cnf,优先级高于my.cnf,改my.cnf不起作用
怎么安全清理僵死连接而不是硬 kill
别一上来就 KILL 所有 Sleep 连接——有些是正常长连接(比如监控、ETL 工具)。重点盯这些:
- 查出空闲太久的连接:
SELECT ID, USER, HOST, DB, COMMAND, TIME, STATE, INFO FROM information_schema.PROCESSLIST WHERE COMMAND = 'Sleep' AND TIME > 300;(>5 分钟的才考虑) - 按用户/IP 归类看异常来源:
SELECT USER, HOST, COUNT(*) FROM information_schema.PROCESSLIST GROUP BY USER, HOST ORDER BY COUNT(*) DESC; - 对确认无用的连接,用
KILL <code>ID; 逐个终止;不要用KILL QUERY,它只停语句,连接还占着 - 更稳妥的做法是调低超时:
SET GLOBAL wait_timeout = 120;(非交互式连接 2 分钟自动断),SET GLOBAL interactive_timeout = 180;(交互式连接 3 分钟)
注意:wait_timeout 和 interactive_timeout 是会话级变量,已存在的连接不会立即响应新设置,只对后续新建连接生效。
应用层最该检查的三处配置
数据库侧调参只是兜底,真正要修的是代码和连接池:
- HikariCP:
maximumPoolSize建议 ≤ MySQLmax_connections的 70%,并打开leak-detection-threshold(比如设为 60000 毫秒),它能打印堆栈帮你定位哪段代码没关Connection - Druid:
remove-abandoned-timeout和log-abandoned-connections必须开,否则泄漏了你也看不见 - 所有 Java 代码里,
Connection、Statement、ResultSet必须在finally块或 try-with-resources 里显式关闭;ORM 框架如 MyBatis 的@Select方法若返回流式结果集(Cursor),也得手动close()
最容易被忽略的一点:MySQL 8.0.14+ 支持管理端口,通过 admin_address 配置独立监听地址,即使普通连接全满,也能从这个端口进——但前提是提前配好、测试过,出事时才来弄就晚了。


















