maxopenconns需按数据库max_connections的60%~80%设置并配合setmaxidleconns、setconnmaxlifetime和setconnmaxidletime协同调优,避免超限报错或连接闲置失效。

MaxOpenConns 不是越大越好,设高了会压垮数据库,设低了会让请求排队卡住——它必须和数据库的 max_connections、业务实际并发压力、以及另外三个配套参数一起调。
MaxOpenConns 设多少才不触发 ERROR 1040: Too many connections
MySQL 默认 max_connections = 151,PostgreSQL 常见为 100~500。如果你的 Go 服务单实例设 SetMaxOpenConns(200),还没算其他服务或后台任务,数据库就直接拒绝新连接。
- 先查真实上限:
SHOW VARIABLES LIKE 'max_connections';(MySQL)或SELECT setting FROM pg_settings WHERE name = 'max_connections';(PostgreSQL) - 生产环境推荐值 = 数据库
max_connections× 0.6 ~ 0.8,留余量给备份、监控、临时 SQL 等 - 别只按 QPS × 耗时硬算:QPS=300、平均耗时 30ms → 理论需 9 个连接,但加 1.5 倍安全系数后应设为 14~16;再和数据库上限比,取小值
- 上线后盯
db.Stats().OpenConnections:长期 ≥ 90%SetMaxOpenConns值,说明不够用;长期 ≤ 30%,大概率设高了
为什么只设 MaxOpenConns 会出 read: connection reset by peer
因为连接池里那些空闲连接,数据库早把它们断了(比如 MySQL 的 wait_timeout=28800),而 Go 还默认一直留着,直到下次复用时才发现连不上。
-
SetMaxIdleConns必须 ≤SetMaxOpenConns,否则 Go 1.12+ 会 panic:"max idle conns exceeds max open conns" -
SetConnMaxLifetime不是保活,是“到期作废”:设为 30 分钟,连接从创建起活满就关,下次新建 -
SetConnMaxIdleTime(Go 1.15+)才是管空闲的:设为 5~10 分钟,让没人用的连接主动释放,防 NAT 或 LB 中间件踢掉 - 典型组合:
db.SetMaxOpenConns(50)→db.SetMaxIdleConns(20)→db.SetConnMaxLifetime(30 * time.Minute)→db.SetConnMaxIdleTime(5 * time.Minute)
db.Stats() 里哪些字段真能帮你定位问题
别只看一次快照,要盯趋势。这几个字段比日志还准:
-
WaitCount持续上涨 → 请求在排队等连接,优先调高SetMaxOpenConns -
InUse == SetMaxOpenConns且长期不回落 → 连接没归还,查rows.Close()是否漏写、事务是否没commit/rollback -
MaxIdleClosed > 0且频繁增长 → 空闲连接回收太猛,适当提高SetMaxIdleConns或延长SetConnMaxIdleTime -
Ping()成功但查询报dial tcp: i/o timeout→ 老连接还在 idle 池里发呆,SetConnMaxIdleTime没设或设太大
最常被忽略的是 SetConnMaxIdleTime:默认为 0(永不过期),云数据库主备切换、RDS 代理超时、甚至公司防火墙策略都可能在你不知情时悄悄断掉空闲连接——这个值不显式设,等于把连接池的“自动清理”功能关掉了。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











