mysql报错“too many connections”常因系统文件描述符不足而非连接数超限;需同步调整limits.conf、systemd limitnofile和my.cnf中max_connections,并关注内存与锁竞争。

MySQL报错“Too many connections”却查不到满连接?先看Threads_connected和max_connections是否真撞线
很多情况下,Too many connections不是因为应用连得太猛,而是MySQL自己被系统卡住了——max_connections设了1000,但实际生效的可能只有214。执行SHOW VARIABLES LIKE 'max_connections';看到的值,未必是MySQL真正能撑住的上限。
关键要看两个地方:
-
SHOW STATUS LIKE 'Threads_connected';—— 当前已建立连接数(含Sleep) -
SHOW STATUS LIKE 'Threads_running';—— 正在干活的连接数,这个才反映真实负载
如果Threads_connected远低于max_connections却仍报错,基本可以断定:系统层文件描述符(fd)不够用了,MySQL想开新连接,OS直接拒绝。
为什么改了max_connections还是没用?ulimit -n和LimitNOFILE才是拦路虎
MySQL每个连接至少占1个文件描述符。你设max_connections = 1000,但OS给mysqld进程只分配了1024个fd,还要预留几十个给日志、socket、配置文件等,实际能用的可能就900出头。更糟的是,systemd启动的MySQL(如CentOS/RHEL/Ubuntu 22.04+)默认受LimitNOFILE限制,哪怕/etc/security/limits.conf改了也没用。
排查路径很直接:
- 查MySQL进程当前fd上限:
cat /proc/$(pgrep mysqld)/limits | grep "Max open files" - 查systemd服务限制:
systemctl show mariadb | grep LimitNOFILE(或mysql) - 查全局用户限制:
ulimit -n(需以mysqld启动用户身份执行)
三者中最小的那个,就是MySQL实际能拿到的fd上限,它会硬性压制max_connections。
永久生效要动三个地方:limits.conf + systemd service + my.cnf
只改一个地方,大概率白忙活。必须同步调整:
- 在
/etc/security/limits.conf末尾加两行(注意用户名或通配符):* soft nofile 65536 * hard nofile 65536
- 在
/usr/lib/systemd/system/mysqld.service(或mariadb.service)的[Service]段加:LimitNOFILE=65536 LimitNPROC=65536
- 在
/etc/my.cnf的[mysqld]段写明:max_connections = 1000
改完别忘了:sudo systemctl daemon-reload && sudo systemctl restart mysqld。重启后立刻验证:cat /proc/$(pgrep mysqld)/limits | grep "Max open files",确认数值已更新,再查SHOW VARIABLES LIKE 'max_connections';是否同步。
调高max_connections后响应反而变慢?内存和锁竞争比连接数更致命
每个连接默认吃掉256KB–1MB内存(取决于sort_buffer_size等会话变量)。设到2000连接,光连接内存就可能干掉2GB。更隐蔽的问题是并发升高后:
- InnoDB行锁争抢加剧,
innodb_row_lock_waits飙升 - 查询排队变长,
Threads_running虽不高,但平均响应时间翻倍 - CPU上下文切换开销陡增,
show status like 'Threads_created';持续上涨说明连接复用率低
所以,max_connections不是越大越好。优先检查应用是否漏关连接、连接池maxIdle是否设得过大、wait_timeout是否还卡在8小时。真正该调的,往往是wait_timeout = 300这类参数,而不是盲目堆数字。











