数据库连接突然断开,TiDB 的内存曲线先升高再掉到零,这些现象值得警惕,但还不能单凭它们认定发生了 OOM。排查应先把操作系统杀进程、数据库主动中止超额查询,以及客户端自身内存不足区分开,再沿着部署资源、SQL 执行和客户端行为逐项定位。
本文依据 PingCAP《TiDB OOM 故障排查》完整整理。核对日期:2026-10-05;当日 stable 页面标识为 TiDB Self-Managed v8.5。变量、旧配置项和实验性功能应以实际集群版本为准。本文只做静态审核,没有连接或操作数据库。

一、从故障现象开始,但不要把症状当结论
客户端可能收到下面的连接错误:
SQL error, errno = 2013, state = 'HY000':
Lost connection to MySQL server during query
在 Grafana 中,重点对齐故障发生时刻,检查三组信号:TiDB > Server > Memory Usage 的 process/heapInUse 是否持续上涨并突然归零;TiDB > Server > Uptime 是否归零;TiDB-Runtime > Memory Usage 的 estimate-inuse 是否持续升高。
tidb.log 中还可能出现内存告警和启动日志。内存告警表示进程存在 OOM 风险,并说明会保存运行中的 SQL 和 heap profile;它本身不等于进程已经被系统杀死。
[WARN] [memory_usage_alarm.go:139]
["tidb-server has the risk of OOM because of memory usage exceeds alarm ratio. Running SQLs and heap profile will be recorded in record path"]
[INFO] [printer.go:33] ["Welcome to TiDB."]
告警阈值对应 memory-usage-alarm-ratio。启动日志与 Uptime 归零可支持“进程重启”的判断,真正的终止原因仍要与内核日志、服务管理器记录一起核对。
二、确认 OOM,再判断是部署问题还是数据库问题
原文建议在 TiDB 所在主机查看操作系统日志:
dmesg -T | grep tidb-server
如果故障时刻附近有 oom-killer、Out of memory 和被杀进程为 tidb-server 的记录,才能把操作系统内存不足与该 TiDB 进程的退出直接关联。下面是原文日志中用于判断的关键记录,省略了硬件和内核背景字段:
Mar 14 16:55:03 localhost kernel: tidb-server invoked oom-killer: gfp_mask=0x201da, order=0, oom_score_adj=0
Mar 14 16:55:03 localhost kernel: Out of memory: Kill process 21945 (tidb-server) score 956 or sacrifice child
Mar 14 16:55:03 localhost kernel: Killed process 21945 (tidb-server), UID 1000, total-vm:33027492kB, anon-rss:31303276kB, file-rss:0kB, shmem-rss:0kB
Mar 14 16:55:07 localhost systemd: tidb-4000.service: main process exited, code=killed, status=9/KILL
仅有 status=9/KILL 也可能是其他来源发送了 SIGKILL,因此应结合前面的内核记录。部分环境限制读取 dmesg,日志也可能被轮转;没有查到这条记录不应反过来证明“未发生 OOM”。
确认 OOM 后,分两路检查。部署方面看容量配置、资源限制和混合部署资源竞争;数据库方面看大查询、大写入、导入、高 SQL 并发或高算子并发,以及资源未释放导致的持续增长。客户端自身 OOM 则应单独追踪,不能与 TiDB 进程 OOM 混为一谈。
三、部署问题:容量、资源限制与混合部署
- 容量规划偏小。操作系统可用内存不足,正常负载也可能逼近进程或主机限制。
- TiUP 资源限制配置不合理。检查
resource_control,尤其是resource_control.memory_limit。主机总内存与进程实际允许使用的内存不是同一个量。 - 同机其他程序抢占资源。混合部署时应把其他应用的内存增长纳入时间线;TiDB 被杀不自动意味着只有 TiDB 自身行为有问题。
四、数据库问题:按内存增长来源逐项缩小范围
先分清查询配额中止
ERROR 1105 (HY000): Out Of Memory Quota![conn_id=54]
这类错误可能是 tidb_mem_quota_query 触发的内存使用控制。它表示查询达到配额后被限制,是保护机制的正常行为,不等同于操作系统已经杀掉 TiDB。需要优化查询或合理规划配额,不能只因看到 “Out Of Memory” 就认定服务重启。
SQL 执行时消耗过多内存
不合适的执行计划会把庞大的中间结果留在内存中。缺少索引、统计信息过期、优化器问题都可能导致这样的计划。原文给出的处理方向包括:增加合适索引、使用支持的算子落盘能力、调整 JOIN 顺序,以及使用 hint 调优。它们应结合具体执行计划选择,不宜一次性盲目修改。
另一种情况是算子或函数无法下推到存储层,大量中间数据需要在 TiDB 侧处理。此时可以改写业务 SQL,或用 hint 引导可下推的算子和函数。执行计划中若有 HashAgg,它的多线程执行虽然较快,也可能占用较多内存;可以评估是否适合使用 STREAM_AGG()。这不是所有查询都适用的替换建议。
高并发也会放大内存需求。减少同时读取的 Region 数量、降低算子并发,可以关注 tidb_distsql_scan_concurrency 和 tidb_executor_concurrency。如果故障时刻 session 并发过高,还应评估增加 TiDB 节点。降低并发可能影响吞吐量,调整后需要在目标负载下验证。
大事务、大写入
事务大小不能直接当作进程所需内存。原文提醒,TiDB 处理事务时的内存占用存在放大,可能达到提交事务大小的 2~3 倍甚至更多。这个数字是容量规划提示,不是所有事务都满足的固定比例。对单个大事务,可以通过拆分降低单次事务规模,并确认拆分后的原子性和业务重试方式仍符合要求。
收集与加载统计信息
TiDB 启动后会加载统计信息,收集统计信息同样消耗内存。可通过指定采样率、只采集需要的列,以及降低 ANALYZE 并发控制开销。
从 v6.1.0 起,tidb_stats_cache_mem_quota 用于限制统计信息缓存内存;tidb_mem_quota_analyze 用于控制更新统计信息的内存。本次进一步核对v8.5变量文档:ANALYZE内存限制仍为实验特性,生产环境可能存在内存统计误差;该变量默认值为-1,非正值表示不限制前后台统计更新任务。它不能作为覆盖所有内存来源的硬保证。
预处理语句不断创建却没有释放
客户端持续创建 Prepared Statement,却没有在用完后执行 DEALLOCATE PREPARE 或调用驱动相应的关闭接口,会让长连接持有越来越多资源。显式释放是正常生命周期的一部分;会话关闭也会释放关联资源。
原文列出了调整 session 生命周期、连接池相关的 wait_timeout 与 max_execution_time,以及使用 max_prepared_stmt_count 限制数量等措施。需要注意,这些控制作用不同:空闲连接超时与语句执行时长限制都不能代替及时关闭预处理语句。连接池的回收策略也要与驱动行为一起核对。
不合适的系统变量配置
tidb_enable_rate_limit_action 对单纯读取场景的内存控制较有效;如果查询还有 JOIN、聚合等计算,启用它可能使某些内存不受 tidb_mem_quota_query 控制,增加 OOM 风险。原文建议关闭该变量,并注明从 v6.3.0 起默认关闭。仍应核实目标版本是否保留该变量、当前值及行为,避免把旧参数说明直接复制到新版本配置。
五、客户端 OOM:看数据流和驱动缓存
如果被耗尽的是应用客户端内存,应检查 Grafana 的 TiDB Details > Server > Client Data Traffic,结合流量趋势和速率判断是否存在网络阻塞。然后核对 JDBC 等驱动的读取方式,例如 defaultFetchSize 配置错误,可能使大量查询结果缓存在客户端。
“使用流式读取”不能仅靠写入一个参数来判断是否生效;要检查具体驱动版本、语句类型和连接设置。数据库服务端内存平稳也不能排除客户端缓存问题。
六、诊断信息应形成一条可复核的时间线
收集信息时同时记录故障时刻、节点、时区、版本和调整前后状态。以下清单对应原文的完整诊断范围。
| 范围 | 应收集的内容 |
|---|---|
| 操作系统与部署 | TiUP resource_control.memory_limit;/proc/meminfo;vm.overcommit_memory;numactl --hardware 与 numactl --show。 |
| 数据库版本与内存控制 | TiDB 版本;tidb_mem_quota_query、memory-usage-alarm-ratio、mem-quota-query、oom-action、tidb_enable_rate_limit_action、tidb_server_memory_limit。 |
| 落盘与统计信息 | oom-use-tmp-storage、tmp-storage-path、tmp-storage-quota、tidb_analyze_version。 |
| 日常基线 | Grafana 的 TiDB > Server > Memory Usage,以及故障时间附近的内存变化。 |
上表保留原文列出的旧配置名,目的在于核对历史或具体版本的有效配置,不是建议同时设置所有同名新旧选项。
定位高内存 SQL 可以交叉使用 TiDB Dashboard 的 SQL 语句分析与慢查询、INFORMATION_SCHEMA.SLOW_QUERY 和 CLUSTER_SLOW_QUERY、各节点 tidb_slow_query.log,以及下面的查询或日志筛选:
grep "expensive_query" tidb.log
SELECT * FROM information_schema.processlist;
processlist 中的 MEM 列可帮助关联 SQL 与内存。原文还建议用 EXPLAIN ANALYZE 查看算子内存,但它会真实执行目标语句;对写操作或昂贵 SQL,必须先评估副作用与额外负载,不能当成只读查看计划。
内存使用率高时,可从 TiDB 的诊断端口采集 profile:
curl -G "http://{TiDBIP}:10080/debug/zip?seconds=10" > profile.zip
{TiDBIP} 是待替换占位符。该命令会发起十秒诊断采集并覆盖当前目录同名文件。诊断端口应仅向受控管理网络开放;profile、慢日志和 SQL 文本可能含业务数据,分享前应审查和脱敏。
还可用以下命令查找自动保存的告警文件位置:
grep "tidb-server has the risk of OOM" tidb.log
告警记录包含是否设置 tidb_server_memory_limit、系统总内存、系统与 TiDB 内存用量、告警比例和 record path。原文样例中的比例为 0.8,路径落在 TiDB 临时存储目录的 record 子目录;这些只是样例值,应读取当前节点实际日志。
原文完整诊断日志示例
以下为原文历史样例,字段和路径保持原样,未在本次执行。
......
Mar 14 16:55:03 localhost kernel: tidb-server invoked oom-killer: gfp_mask=0x201da, order=0, oom_score_adj=0
Mar 14 16:55:03 localhost kernel: tidb-server cpuset=/ mems_allowed=0
Mar 14 16:55:03 localhost kernel: CPU: 14 PID: 21966 Comm: tidb-server Kdump: loaded Not tainted 3.10.0-1160.el7.x86_64 #1
Mar 14 16:55:03 localhost kernel: Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS rel-1.14.0-0-g155821a1990b-prebuilt.qemu.org 04/01/2014
......
Mar 14 16:55:03 localhost kernel: Out of memory: Kill process 21945 (tidb-server) score 956 or sacrifice child
Mar 14 16:55:03 localhost kernel: Killed process 21945 (tidb-server), UID 1000, total-vm:33027492kB, anon-rss:31303276kB, file-rss:0kB, shmem-rss:0kB
Mar 14 16:55:07 localhost systemd: tidb-4000.service: main process exited, code=killed, status=9/KILL
......
["tidb-server has the risk of OOM because of memory usage exceeds alarm ratio. Running SQLs and heap profile will be recorded in record path"] ["is tidb_server_memory_limit set"=false] ["system memory total"=14388137984] ["system memory usage"=11897434112] ["tidb-server memory usage"=11223572312] [memory-usage-alarm-ratio=0.8] ["record path"="/tmp/0_tidb/MC4wLjAuMDo0MDAwLzAuMC4wLjA6MTAwODA=/tmp-storage/record"]
延伸阅读与来源
进一步分析可阅读 TiDB 内存调优、TiKV 内存调优,并从原页进入对应系统变量与统计信息文档。
原文与版权归属:PingCAP 及 TiDB 文档贡献者,《TiDB OOM 故障排查》。原页无个人署名,页脚标示 © 2026 PingCAP。原创示意图另附;未将项目代码许可推定为文档许可。












暂无评论内容