答案是:先查Threads_connected与Threads_running是否严重失衡,再确认wait_timeout和连接池配置是否匹配。出现“Too many connections”时90%是应用未释放连接或连接池配错,而非max_connections过小;Threads_connected接近上限但Threads_running极低,表明大量Sleep连接堆积;调大max_connections需同步解决系统文件描述符、内存开销及连接池idleTimeout ≤ wait_timeout等三重限制。

不是 max_connections 设得太小,而是应用没关连接或连接池配错了。 临时调大 max_connections 只能撑几分钟,真正卡死的往往是大量 Sleep 状态连接堆在那儿不释放。
怎么快速确认是不是真连满了
别急着改配置。哪怕应用连不上,用 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 很小(比如 2/500),说明几百个连接全卡在 Sleep,基本就是应用层泄漏或连接池 idle 超时比 MySQL 的 wait_timeout 还长。
为什么 SET GLOBAL max_connections 经常失效
这条命令看着快,实际有三道硬门槛:
- Linux 系统级文件描述符限制拦着:
ulimit -n默认常为 1024,max_connections设到 1000 就可能失败 - Docker 容器里没加
--ulimit nofile=65536:65536,光改 MySQL 配置没用 - 已经连不上了?那
SET GLOBAL根本执行不了——得靠kill -TERM主进程(不是mysqld_safe)安全重启
更关键的是:内存扛不住。每个连接平均吃 512KB~2MB,设到 2000 连接,光连接本身就要 1~4GB 内存,容易触发 OOM。
连接池配置比 MySQL 参数更关键
多数线上事故根子在应用侧。比如 Druid 这类池子,常见错配:
-
max-active设得比max_connections还高,多个服务一起压就爆 -
min-idle和max-wait没调,连接用完不归还、等超时才扔,堆满 Sleep -
remove-abandoned-timeout没开,泄漏连接永远不回收
必须保证:连接池的空闲回收时间(如 Druid 的 time-between-eviction-runs-millis + min-evictable-idle-time-millis)短于 MySQL 的 wait_timeout(建议设成 300 秒)。否则池子以为连接还活着,MySQL 却早把它断了,下次取出来直接报错。
最易被忽略的一点:wait_timeout 和 interactive_timeout 必须同时调,且值一致。很多 DBA 只改了前者,后者仍为 8 小时,导致交互式客户端(比如运维脚本、某些 ORM 初始化连接)长期占着连接不放。


















