先别急着调高 max_connections,90% 的 "Too many connections" 报错并非连接数不够用,而是连接未被释放、持续堆积占坑所致——必须首先确认是否真的达到连接上限,再决定是否扩容。
如何快速判断是否真正达到连接上限?即便应用已无法连接,MySQL 仍会为 SUPER 权限预留一个紧急连接通道(max_connections + 1),因此仍可通过 socket 登录排查:
- 执行
SHOW VARIABLES LIKE 'max_connections';—— 查看连接上限,默认通常为 151 - 执行
SHOW STATUS LIKE 'Threads_connected';—— 查看当前已建立的连接数 - 执行
SHOW STATUS LIKE 'Threads_running';—— 查看当前正在执行任务的线程数
如果 Threads_connected 接近上限,而 Threads_running 极低(例如 2/498),说明大量连接处于 Sleep 空闲状态,通常是因为应用未正确关闭连接,或连接池 idleTimeout 设置大于 MySQL 的 wait_timeout 所致。

临时扩容为何经常失效
SET GLOBAL max_connections = 1000; 看似快捷,但存在三道硬性门槛:
- Linux 系统级文件描述符限制:
ulimit -n默认值通常为 1024,设为 1000 即可能失败;Docker 容器中若未添加--ulimit nofile=65536:65536,仅修改 MySQL 参数无效 - 如果已经无法连接,该命令根本无从执行——需通过
kill -TERM主进程(非mysqld_safe)进行安全重启 - 内存资源不足:每个连接平均消耗 512KB~2MB,若设为 2000 连接,仅连接本身就需要 1~4GB 内存,极易触发 OOM 机制
连接池配置比 MySQL 参数更为关键
多数线上故障根源在于应用侧。以 Druid 或 HikariCP 为例,常见配置错误包括:
max-active(或maximumPoolSize)设置高于max_connections,多个服务并发压力下立刻爆满min-idle与max-wait未合理调整,连接使用后未归还、等待超时才释放,导致Sleep连接堆积idleTimeout(连接池)大于wait_timeout(MySQL),连接池认为连接仍有效,MySQL 却已单方面断开,后续复用时报错或卡死
正确做法是:连接池 idleTimeout 必须 ≤ MySQL 的 wait_timeout,建议初期均设为 300 秒(5 分钟),再根据业务情况微调。
永久生效需要修改哪些配置
编辑 /etc/my.cnf 或 /etc/mysql/my.cnf,在 [mysqld] 段添加:
max_connections = 500wait_timeout = 300interactive_timeout = 300max_user_connections = 100
注意:max_user_connections 用于防止单个应用(如某个微服务)耗尽所有连接,为管理账号和其他服务预留空间。修改后务必验证语法:mysqld --validate-config,并确认未被其他配置文件覆盖(使用 mysqld --verbose --help | grep "Default options" 查看加载顺序)。
真正的难点并非调整数字,而是确认每个 Sleep 连接背后是否存在未提交事务、慢查询或异常退出的脚本——这些隐患才是连接反复爆满的根本诱因。
