SetMaxOpenConns必须按TiDB Server内存上限反推,不能套用MySQL经验:每连接耗数十KB至数MB内存,1000空闲连接可压垮16GB实例;8GB/16GB/32GB内存建议上限分别≤400/800/1600,并严格配对SetMaxIdleConns(设为1/2~2/3)与SetConnMaxLifetime(云环境推荐2分钟)。

SetMaxOpenConns 必须按 TiDB Server 内存上限反推,不能套用 MySQL 经验
TiDB 的 max_connections 配置只是个软限制,真瓶颈在 TiDB Server 的内存。每个连接平均吃掉几十 KB 到几 MB 内存(取决于会话变量、预处理缓存和排序缓冲区),1000 个空闲连接就可能压垮一个 16GB 内存的 TiDB 实例。盲目设 SetMaxOpenConns 为 200 或 500,容易触发 ERROR 1105 (HY000): Out of memory,而不是传统 MySQL 那种明确的 Too many connections。
实操建议:
- 先查当前 TiDB 实例内存规格(如 8GB / 16GB / 32GB),再按每连接 ≈1MB 保守估算上限:8GB → 建议
SetMaxOpenConns≤ 400;16GB → ≤ 800 - 生产环境务必配合
tidb-server的mem-quota-query和oom-action=cancel使用,防单查询耗尽全局内存 - 别信
SHOW VARIABLES LIKE 'max_connections'返回值——TiDB 默认 4096 是“允许连上”,但连上后是否能活下来,取决于内存是否够分
SetMaxIdleConns 和 SetConnMaxLifetime 必须严格配对,云环境建议 2 分钟
TiDB 的连接不是“连上就完事”。PD 调度、Region 迁移、TiKV 节点重启都可能导致连接在服务端静默失效。不设 SetConnMaxLifetime,空闲连接会在 NAT 网关或防火墙超时后断开,下次复用直接报 read: connection reset by peer;只设 SetMaxIdleConns 不清理,又会导致大量 idle 连接堆积在 TiDB Server 上,占内存、锁事务状态、拖慢 GC。
推荐组合:
-
SetMaxIdleConns设为SetMaxOpenConns的 1/2~2/3(如最大 600 → 空闲 300) -
SetConnMaxLifetime设为2 * time.Minute(云环境主备切换快,2 分钟比 5 分钟更安全) - 绝对不要设
SetConnMaxLifetime为0或time.Hour——长期存活连接极易在 TiDB 侧积压idle in transaction,尤其在乐观事务未提交时
启动时 db.Ping() 失败 ≠ DSN 错,要检查 TiDB Server 监听地址和 TLS 配置
GORM 的 gorm.Open() 只初始化连接池结构,不建真实连接。db.Ping() 才是第一次拨号。常见现象是日志显示 “DB initialized”,但首请求直接 panic —— 因为 db.Ping() 被漏掉了,或失败后没处理。
排查要点:
- 确认 TiDB Server 监听的是
0.0.0.0:4000,不是127.0.0.1:4000(K8s/Docker 环境高频踩坑) - 若 TiDB 开启了
security.require-secure-transport = true,DSN 必须带&tls=skip-verify或完整 CA 链,否则db.Ping()报dial tcp: i/o timeout - GORM v2 中
db.Ping()已弃用,必须用db.Session(&gorm.Session{}).Ping(),否则永远不触发真实连接校验
timezone=UTC 和 parseTime=true 是硬性要求,loc=Local 会引发静默时间偏移
TiDB 的 TSO 时间戳是 UTC 纳秒级,由 PD 统一授时。Go 驱动若用本地时区解析 DATETIME/TIMESTAMP,会导致插入和读取的时间字段偏移几小时。这不是报错,而是静默偏差:MVCC 版本错乱、事务可见性判断失效、甚至 SELECT ... FOR UPDATE 锁错行。
DSN 必须包含:
-
timezone=UTC:强制驱动按 UTC 解析所有时间类型,与 PD 授时对齐 -
parseTime=true:让 MySQL 驱动把时间字段转成time.Time,否则Scan到 struct 会 panic 或返回空字符串 - 禁用
loc=Local或loc=Asia%2FShanghai—— 它们和timezone=UTC冲突,且 TiDB 不依赖客户端时区做任何计算
真正麻烦的不是连不上,而是连上了却在时间维度上悄悄出错——这种问题在线上压测或跨时区业务中才暴露,回溯成本极高。


















