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

别急着改 max_connections,90% 的 “Too many connections” 报错根本不是它太小,而是连接泄漏、空闲堆积或内存失控引发的连锁反应。
怎么看当前连接压力是否真实?
只查 SHOW VARIABLES LIKE 'max_connections' 没用。真正要盯的是三个状态值:
-
Threads_connected:当前挂着的连接总数(含大量Sleep) -
Threads_running:此刻真正在执行 SQL 的活跃线程数 -
Max_used_connections:实例启动以来的历史峰值
如果 Threads_connected 长期 > 80% 的 max_connections,但 Threads_running 常年只有个位数,说明是空闲连接没释放——大概率是应用没关连接,或 wait_timeout 太大;如果 Max_used_connections 接近甚至等于 max_connections,才说明真的踩线了,必须干预。
怎么算一个安全又够用的值?
按内存算比看 CPU 核心数靠谱得多。每个连接实际内存开销 = thread_stack(默认 256KB) + 线程级 buffer(sort_buffer_size、read_buffer_size 等)。这些 buffer 是“用时才分配,但一人一份”,设成 4MB,300 个连接就吃掉 1.2GB。
- 先跑
SHOW STATUS LIKE 'Max_used_connections';,拿到历史峰值 - 再核对应用侧连接池总规模:比如 4 台服务 × HikariCP 的
maximumPoolSize = 50→ 理论峰值 200,加 30% 余量 ≈ 260 - 取两者较大值,向上取整到 50 的倍数(如 300),作为起步值
- 若
Max_used_connections长期稳定在 80 以下,说明默认 151 已足够,硬调只会放大内存风险
改完为什么 MySQL 启不起来或运行中崩溃?
max_connections 不是孤立参数。它直接消耗文件描述符(fd),每个连接至少占 1 个 fd,外加日志、表缓存等开销。系统限制太低,MySQL 要么启动失败,要么被 OOM killer 杀掉。
- 检查当前限制:
ulimit -n;要求:ulimit -n ≥ max_connections + 200 - 永久生效需改
/etc/security/limits.conf,加两行:mysql soft nofile 4096和mysql hard nofile 4096(数值按你设的max_connections推算) - systemd 管理的服务还需改单元文件(如
/usr/lib/systemd/system/mysqld.service),在[Service]下加LimitNOFILE=3500和LimitNPROC=3500,再执行systemctl --system daemon-reload && systemctl restart mysqld
为什么调高后反而更慢甚至 OOM?
关键陷阱在那些“悄悄涨起来”的线程级 buffer 参数。生产环境建议除 thread_stack(保持默认即可)外,其他如 sort_buffer_size、join_buffer_size 显式设为 256K~512K,千万别留空或设成 2M+。
验证方式:执行 SHOW VARIABLES,重点盯这几个值。特别注意 sort_buffer_size ——排序时才分配,但一旦触发就是独享一份,高并发下极易成为内存黑洞。很多线上事故,都是因为这个参数被误设为 4MB,而连接数一冲到 300,瞬间吃掉 1.2GB 内存。











