答案是连接泄漏、空闲堆积或内存失控所致——90%的“too many connections”并非max_connections过小,需先查max_used_connections历史峰值、核对应用连接池总规模,再同步调ulimit、systemd限制及线程级buffer参数。

别急着调高 max_connections,90% 的“Too many connections”根本不是连接数不够,而是连接泄漏、空闲连接堆积或单连接内存失控导致的连锁崩溃。
先看历史峰值再定目标值
盲目设 max_connections = 1000 是最常见也最危险的操作。真实合理值必须基于你自己的业务水位:
- 执行
SHOW STATUS LIKE 'Max_used_connections';,查过去最高用过多少连接(不是当前值) - 核对应用侧连接池总规模:比如 4 台服务 × HikariCP 的
maximumPoolSize = 50,理论峰值是 200,加 30% 余量 ≈ 260 - 取两者较大值,向上取整到 50 的倍数(如 300),作为起步值
- 如果
Max_used_connections长期稳定在 80 以下,说明默认 151 已足够,硬调只会放大风险
改配置必须同步改 ulimit 和 systemd 限制
max_connections 不是孤立参数。MySQL 启动时会预分配文件描述符(fd),每个连接至少占 1 个 fd,外加日志、表缓存等开销。系统限制太低,服务根本起不来,或运行中突然被 OOM killer 杀掉:
- 检查当前限制:
ulimit -n;要求:ulimit -n≥max_connections+ 200 - 永久生效需改
/etc/security/limits.conf,添加两行:mysql soft nofile 4096和mysql hard nofile 4096(假设你设max_connections = 3800) - 在
my.cnf的[mysqld]段写死:max_connections = 300(别用SET GLOBAL临时改,重启就丢) - systemd 管理的服务还需改单元文件:
/usr/lib/systemd/system/mysqld.service,在[Service]下加LimitNOFILE=3500和LimitNPROC=3500,再执行systemctl --system daemon-reload && systemctl restart mysqld
严控线程级 buffer 参数防内存爆炸
很多人按“每连接 256KB”估算内存,结果一上线就 OOM。实际单连接内存 = 基础栈 + 动态 buffer,而 sort_buffer_size、read_buffer_size、join_buffer_size 是线程级分配——设成 4MB,300 个连接就吃掉 1.2GB:
- 生产环境建议:除
thread_stack(默认 256KB,够用)外,其他 buffer 类参数保持默认或显式设为256K~512K - 验证方式:
SHOW VARIABLES输出里重点盯这几个值,别让它们悄悄涨到2M+ - 特别注意:
sort_buffer_size在排序时才分配,但一旦触发就是独享一份,高并发下极易成为内存黑洞
必须配用户级连接限制(MAX_USER_CONNECTIONS)
全局 max_connections 调高治标不治本,MAX_USER_CONNECTIONS 才能精准隔离风险:
- 给已有用户加限制:
ALTER USER 'dev_user'@'localhost' WITH MAX_USER_CONNECTIONS 5;(立即生效,不用FLUSH PRIVILEGES) - 若用户有多个 host(如
'dev_user'@'192.168.%'和'dev_user'@'localhost'),必须分别设置 - 验证是否生效:
SELECT User, Host, Max_user_connections FROM mysql.user WHERE User = 'dev_user';,确保返回值是你设的数字,不是 0 或 NULL - 配合
wait_timeout = 630(比连接池idleTimeout大 30 秒)防止空闲连接长期挂起
真正卡住 MySQL 的往往不是连接上限,而是那些 Sleep 超 60 秒却没释放的连接、未提交的事务、或被 buffer 参数悄悄吃掉的内存。这些点不查清,调再高的 max_connections 都只是给崩溃多续几秒。











