结论:临时救急用SET GLOBAL max_connections,但不改连接池和超时配置则无效;90%的“Too many connections”源于连接未释放、慢查询或连接池配置错误。

直接说结论:临时救急用 SET GLOBAL max_connections,但不改连接池和超时配置,改了也白改;真正压垮 MySQL 的,90% 不是连接数上限低,而是连接没释放、慢查询卡住、或连接池配错。
怎么快速确认是不是真爆满了?
别一看到「Too many connections」就去调 max_connections。先连上(哪怕用 mysql --socket=/var/run/mysqld/mysqld.sock -u root 绕过网络),执行这三条:
-
SHOW VARIABLES LIKE 'max_connections';—— 看上限,MySQL 5.7/8.0 默认才 151,中小业务早就不够用了 -
SHOW STATUS LIKE 'Threads_connected';—— 看当前占了多少名额,包含大量Sleep连接 -
SHOW STATUS LIKE 'Threads_running';—— 看真正干活的线程数,如果这个值接近max_connections,才是真过载
如果 Threads_connected 高但 Threads_running 很低,说明连接堆着没释放,问题在应用层或超时设置,不是数据库扛不住。
临时调大 max_connections 为什么经常失效?
你执行了 SET GLOBAL max_connections = 2000;,但过几分钟又报错,大概率踩了这三个坑:
- 操作系统级限制没放开:
ulimit -n小于新设的连接数,Linux 默认常为 1024,max_connections超过它就自动被截断(MariaDB 尤其明显) - systemd 服务限制没改:CentOS/RHEL 8+ 下,
mariadb.service或mysqld.service文件里必须加LimitNOFILE=65536,否则改了配置也加载不上 - 应用连接池没同步调整:比如 HikariCP 的
maximumPoolSize还是 20,但后端max_connections已调到 2000,结果所有请求全挤在那 20 个连接上反复复用,连接状态疯狂切换成Sleep,反而更容易触发Cleaning up卡顿
连接池和超时参数必须一起动
光调数据库参数治标不治本。重点看这几个应用侧配置:
-
wait_timeout和interactive_timeout:MySQL 默认是 28800 秒(8 小时),线上建议缩到 300–600 秒,避免空闲连接长期占坑 - 连接池的
idleTimeout(如 HikariCP)必须 ≤ MySQL 的wait_timeout,否则连接池会把“已超时但 MySQL 没杀”的连接继续塞给业务,下一次使用直接报错 - 务必启用
testOnBorrow或validationTimeout:防止拿到一个 MySQL 已经断开但连接池还没感知的“脏连接” - 查
SHOW PROCESSLIST时如果大量出现State: Killing或Cleaning up,基本可断定是慢查询 + 连接未关闭双杀,优先砍掉UNION ALL全表扫描这类 SQL,比调参快十倍
最后提醒一个容易被忽略的点
max_connections 调太高有反效果:每个连接至少消耗 256KB 内存(取决于 sort_buffer_size 等),设到 3000 以上又没配够 innodb_buffer_pool_size,MySQL 会频繁换页、swap,CPU 不高但响应极慢——这时候看监控像“假死”,实际是内存资源争抢导致的吞吐坍塌。


















