mysql的max_connections并非越大越好,过高会导致内存溢出和系统文件描述符不足;需根据实际峰值预留20%余量,上限不超max(500, 实际峰值×1.2),并同步调高系统级open files限制。

max_connections设太高反而会压垮服务器
MySQL的max_connections不是越大越好。每个连接至少占用数MB内存(线程栈、缓存、临时表等),设成1000却只有2GB内存的机器,可能刚启动就OOM。Linux还可能因ulimit -n限制无法真正打开那么多文件描述符,导致实际可用连接远低于配置值。
实操建议:
- 先查真实峰值:
SHOW STATUS LIKE 'Threads_connected';和历史监控(比如Prometheus+mysqld_exporter)里过去7天最高值 - 预留20%余量,但上限别超
max(500, 实际峰值 × 1.2);小业务100–200足够 - 改完必须重启MySQL或用
SET GLOBAL max_connections = N;(注意:动态设置在重启后失效) - 同步检查系统级限制:
cat /proc/$(pidof mysqld)/limits | grep "Max open files",不够就调/etc/security/limits.conf
wait_timeout太长会让空闲连接占着茅坑
默认8小时的wait_timeout对Web应用极其危险——应用层没及时close,连接就挂着不动,慢慢吃光max_connections。你看到Too many connections错误,大概率不是并发真高,而是几百个“僵尸连接”在睡觉。
实操建议:
- Web应用统一设为60–300秒(5分钟足够处理绝大多数请求+重试)
- 区分场景:应用连接池用
wait_timeout,交互式客户端(如mysql命令行)用interactive_timeout,后者可稍长 - 验证是否生效:
SHOW VARIABLES LIKE '%timeout%';,再连一个新会话查SELECT @@wait_timeout; - Java应用要确认连接池(如HikariCP)的
connection-timeout和idle-timeout比MySQL的wait_timeout更短,否则池子自己就卡住
连接没释放?先盯紧应用层的close逻辑
调低wait_timeout只是兜底,根子在代码。常见错误是try-catch里忘了conn.close(),或者用了Spring @Transactional但没配transactionManager,导致事务不提交、连接不归还。
实操建议:
- 加监控:定期跑
SELECT ID, USER, HOST, DB, COMMAND, TIME, STATE FROM information_schema.PROCESSLIST WHERE TIME > 60;,看有没有TIME超长的Sleep连接 - Java项目检查是否有
Connection、Statement、ResultSet没在finally里close(或没用try-with-resources) - PHP用
mysqli时,确保mysqli_close($conn)被执行;PDO则依赖析构,但长脚本里建议显式$pdo = null; - Node.js用
mysql2要注意pool.releaseConnection(conn)别漏掉,尤其在Promise链出错时
连接数突然飙升?优先查慢查询和锁等待
如果连接数不是缓慢爬升,而是某次发布/活动后陡增,90%不是配置问题,是SQL卡住了。一个没索引的SELECT * FROM orders WHERE status = 'pending'扫千万行,会把连接hang住,后续请求全排队等着,连接数瞬间飙到上限。
实操建议:
- 立刻查:
SHOW PROCESSLIST;看大量连接是否卡在Sending data、Locked或Copying to tmp table - 开慢日志:
SET GLOBAL slow_query_log = 'ON'; SET GLOBAL long_query_time = 1;,然后抓最近10分钟的慢SQL - 用
pt-query-digest分析,重点看Rows_examined高、Using temporary/Using filesort多的语句 - 紧急缓解:杀掉最老的Sleep连接(
KILL N;),但必须同步优化SQL,否则10分钟后照旧
真正难的不是改两个参数,是得同时盯住MySQL状态、应用连接池行为、SQL执行效率这三层。少看一眼,max_connections调再大也白搭。











