先确认是否真连满:用socket直连执行show variables like 'max_connections'和show status like 'threads_connected',若后者接近上限且threads_running极低,说明大量连接卡在sleep状态未释放,根源是应用未关闭连接或连接池配置失当。

不是连接数不够,而是连接没被释放——先看 Threads_connected 和 Threads_running 的差值,再查 PROCESSLIST 里 Sleep 超时的连接。
怎么看当前连接是否真爆满
连不上 MySQL 时,别急着改 max_connections。先用 socket 登录(绕过 TCP 限制)执行三行命令:
-
SHOW VARIABLES LIKE 'max_connections';—— 看上限,云数据库可能设 1000+,但默认仍是 151 -
SHOW STATUS LIKE 'Threads_connected';—— 当前所有连接数,包括 Sleep 状态 -
SHOW STATUS LIKE 'Threads_running';—— 正在执行 SQL 的线程数
如果 Threads_connected 是 498、Threads_running 只有 23,说明 475 个连接在空转,问题不在并发量,而在应用没关连接或连接池配置失当。
怎么定位泄漏源:重点关注 SHOW PROCESSLIST 输出
SHOW PROCESSLIST; 是唯一能看清“谁占着不放”的命令。需用 root 或具备 PROCESS 权限的账号,否则看不到其他用户连接。重点筛这三类:
-
State = 'Sleep'且Time > 300:空闲超 5 分钟,基本是应用获取连接后未调用close(),或连接池min-idle设得过高、remove-abandoned-timeout未启用 -
State是'Sending data'、'Locked'或'Updating'且Time持续增长:SQL 卡住,可能是慢查询、锁等待、大事务未提交 - 同一
User+Host出现几十个连接:大概率是某个微服务实例泄漏,比如 Spring Boot 应用重启后旧进程残留,或 PHP 脚本异常退出未归还连接
为什么连接池配置错会导致连接堆积
连接池不是开得越大越好,关键参数要匹配业务行为:
-
max-active(如 Druid 的spring.datasource.druid.max-active=50)设太高,多个服务加起来就打爆数据库 -
min-idle过高 +time-between-eviction-runs-millis过长 → 空闲连接长期不回收 - 没开
remove-abandoned-on-borrow或remove-abandoned-timeout→ 异常场景下泄漏连接无法自动清理 - 应用代码里没在
finally块中调用connection.close(),尤其在 try-catch 中抛出异常后直接 return
Druid 默认不启用连接回收,必须显式配 remove-abandoned=true 和 remove-abandoned-timeout=60 才会踢掉卡住的连接。
Linux 层限制常被忽略:ulimit -n 决定 MySQL 能否真正用满 max_connections
即使你把 max_connections 设成 2000,若系统 ulimit -n 返回 1024,MySQL 启动时会自动向下取整,日志里会出现 Could not increase number of max_open_files。验证方式:
- 查 MySQL 实际生效值:
SELECT @@global.max_connections;,别信配置文件 - 查系统限制:
cat /proc/$(pgrep mysqld)/limits | grep "Max open files" - 永久修复需改
/etc/security/limits.conf和 MySQL service 文件里的LimitNOFILE
最易被跳过的点:MySQL 8.0.22+ 用了 SET PERSIST 后,my.cnf 里改 max_connections 会被忽略,得去查 mysqld-auto.cnf。











