数据库连接耗尽最常见原因是连接池配置过小且并发请求高,其次为连接未正确关闭、长事务或慢查询阻塞、连接池与数据库最大连接数不匹配。
数据库连接耗尽最常见原因是连接池最大值(如 maxPoolSize)设得太低,而应用短时间内发起大量查询。比如 Spring Boot 默认 HikariCP 的 maximumPoolSize 是 10,若接口 QPS 达到 50 且平均响应时间 200ms,理论瞬时连接需求就可能突破 10(50 × 0.2 = 10),实际因排队和重试很容易打满。
实操建议:
SHOW STATUS LIKE 'Threads_connected';,PostgreSQL 查 SELECT count(*) FROM pg_stat_activity;
maximumPoolSize、connectionTimeout 和 idleTimeout,避免空闲连接长期不释放active、idle、pending 指标,HikariCP 可通过 JMX 或 /actuator/metrics/hikaricp.connections.active 获取Java 中忘记在 finally 块或 try-with-resources 中关闭 Connecti、
Statement、ResultSet,或 Go 中漏掉 rows.Close(),都会让连接一直被占用,直到超时或进程重启。
典型现象是连接数缓慢上涨,且 SHOW PROCESSLIST(MySQL)里能看到大量 Sleep 状态连接,状态持续几分钟以上。
实操建议:
connection.createStatement()
autoCommit=true),否则事务不结束会锁住连接@Transactional 方法没有被同类内非代理方法调用,否则事务失效,连接无法按预期释放一个执行 30 秒的 UPDATE 语句会独占一个连接整整半分钟,期间该连接无法复用。如果这类语句频繁出现,连接池很快被占满,新请求只能等待或失败。
更隐蔽的是隐式事务:比如 MySQL 在 autocommit=false 下执行一条 SELECT 后没提交,后续所有操作都在同一事务中,连接就一直挂着。
实操建议:
wait_timeout 和 interactive_timeout(默认 28800 秒),但不能替代应用层优化SET SESSION max_execution_time = 5000;(MySQL 5.7+),强制中断超时 SQLEXPLAIN 分析慢查询是否缺少索引,避免全表扫描拖住连接应用端配了 maximumPoolSize=100,但 MySQL 的 max_connections 只有 50,结果一半连接永远拿不到,报错通常是 Too many connections 或 HikariCP 的 Connection is not available, request timed out after 30000ms。
还要注意中间件影响:比如用了读写分离代理(MyCat、ShardingSphere),它本身也维护连接池,会额外消耗后端数据库连接。
实操建议:
SHOW VARIABLES LIKE 'max_connections';,并结合业务预估总连接需求(应用实例数 × 单实例连接池大小 + 代理开销 + 运维工具连接)ulimit -n)会导致创建失败,Linux 默认常为 1024max_connections 的 60%~80%,留出余量给备份、监控等后台任务真正难排查的往往是组合问题:比如连接池偏小 + 几个慢查询 + 一处忘了 close,三者叠加才触发耗尽。监控必须覆盖应用连接池指标、数据库活跃连接、SQL 执行时长三个层面,缺一不可。