SQL 如何排查“连接数爆满” Too many connections 的来源进程

2次阅读

首要动作是执行SHOW PROCESSLIST或查询information_schema.PROCESSLIST过滤非Sleep且Time>300的会话,通过Host列定位客户端IP和端口,结合Command、State、Time判断连接异常类型,并配合应用侧连接池监控与日志分析根因。

SQL 如何排查“连接数爆满” Too many connections 的来源进程

查当前活跃连接和来源 IP

mysqlToo many connections 时,首要动作不是重启,而是快速定位谁在占着连接不放。执行:

SHOW PROCEsslIST;

重点看 Host 列(格式通常是 xxx.xxx.xxx.xxx:port),能直接暴露客户端 IP 和端口Command 列为 SleepTime 值很大(比如 > 300 秒)的,大概率是应用没正确关闭连接;StateSending dataLocked 的,则可能卡在慢查询或锁等待上。

如果权限足够,更推荐用:

SELECT ID, USER, HOST, DB, COMMAND, TIME, STATE, INFO FROM information_schema.PROCESSLIST WHERE COMMAND != 'Sleep' OR TIME > 300;

这样过滤掉大量无意义的空闲连接,聚焦可疑会话。

区分应用连接池与真实客户端

看到 HOST127.0.0.1:xxxxxlocalhost,别急着认为是本地脚本——它更可能是中间件(如 nginx + php-FPM、tomcatnode.js 进程)发起的连接。真实来源需结合应用日志或部署结构判断:

  • java 应用常用 HikariCP/Druid,检查 spring.datasource.hikari.maximum-pool-size 是否设得过大(如 100+),且未配置 connection-timeoutidle-timeout
  • PHP 的 mysqlnd 默认不复用连接,mysqli 每次 new 一个实例就新建连接,容易在循环里失控
  • pythonpymysqlmysql-connector-python 若没用 with 或显式 close(),连接会在 GC 前一直挂着

单纯靠 MySQL 端无法区分“同一个 IP 下的多个进程”,必须配合应用侧连接池监控(如 HikariCP 的 /actuator/metrics/hikaricp.connections.active)。

临时释放连接 + 防止雪崩

确认某类连接异常后,可手动 kill:

KILL 12345;

但注意:KILLSleep 状态有效,对正在执行的事务可能只中断客户端,服务端仍需完成回滚;批量杀连接慎用,避免误杀核心业务会话。

更稳妥的做法是临时调高上限,争取排查时间:

SET GLOBAL max_connections = 500;

但这只是掩耳盗铃——真正要改的是应用行为。常见错误配置包括:

  • wait_timeoutinteractive_timeout 设为 0(永不过期),导致空闲连接永远不释放
  • 应用代码中 try 里开连接、finally 忘了 close(),尤其在异常分支下
  • 使用连接池却把 min-idle 设太高(如 50),冷启动时直接占满一半连接数

长期监控该盯哪些指标

靠人工 SHOW PROCESSLIST 只能救火,不能根治。上线后必须盯住:

  • MySQL 的 Threads_connected(当前总连接数) vs max_connections,持续 > 80% 就该预警
  • 应用侧的连接池 active / idle / pending 数,比数据库端更早暴露泄漏苗头
  • 慢查询日志中 Rows_examined 极高但返回行数极少的语句——这类查询会长时间占用连接,拖垮整个池

很多团队卡在“知道连接多”,但没打通“应用连接池 → 数据库连接 → 网络链路”的全链路追踪,结果每次都是 kill 完事,过两天又爆。真正的瓶颈往往不在 MySQL 配置,而在某段没加超时的 JDBC URL 或某个忘记 close 的 ResultSet

text=ZqhQzanResources