TiDB OOM Errors fall into two types — a full node crash triggered by the OS, or a single query cancelled by TiDB's own memory controls. This guide walks through how to confirm which occurred, identify the SQL patterns most responsible (HashJoin, HashAgg, large transactions, stale statistics), configure the four key memory parameters, enable disk spill as a safety net, and verify production readiness with a structured checklist.
Abishek S August 26, 2026
TiDB OOM Errors tend to strike at the worst possible time — during peak traffic, a large data migration, or at 2 AM when no one is watching. The immediate fix is usually simple: restart TiDB. The harder part is troubleshooting TiDB out of memory conditions well enough to understand what actually caused the OOM and making sure it does not happen again.
This guide explains how TiDB uses memory, what causes OOM conditions, how to diagnose them, and which configuration parameters and SQL patterns can help prevent future incidents. For the authoritative reference, see PingCAP's official TiDB memory control documentation.
Repeated OOM incidents usually point to something deeper than a single bad query. Common contributing factors include:
Mafiree's TiDB Performance and Query Optimization Services can help identify the root cause through configuration reviews, query optimization, and performance audits.
Before troubleshooting an OOM event, determine which type of OOM occurred. The response is different depending on whether the operating system killed TiDB or whether TiDB cancelled an individual query.
The operating system ran out of available memory and killed the TiDB process — active connections drop, running queries terminate, and TiDB restarts. Applications may see connection failures in the meantime. This is the more serious type of OOM, since the entire server process is affected.
TiDB's internal memory controller terminated the query before the server itself ran out of memory. The node stays healthy — this is the protection mechanism working as designed. Still worth investigating why the query needed that much memory, but it's a fundamentally different problem than a server crash.
tidb_memory_usage_alarm_ratio to 0.7 here.
tidb_server_memory_limit threshold.
SET GLOBAL tidb_memory_usage_alarm_ratio = 0.7;
This allows TiDB to warn you before memory usage reaches a critical level.
Before changing any configuration, confirm whether the OOM was caused by the operating system or TiDB's own memory manager.
This tells you whether the Linux kernel killed the TiDB process.
dmesg -T | grep tidb-server
If the kernel killed TiDB, you'll see something like this:
This confirms that the OS terminated the process.
This line means TiDB restarted — it's a useful timestamp anchor for identifying when it happened.
On TiDB → Server → Memory Usage, watching memory over time is one of the fastest ways to confirm a restart: a pattern that gradually increases, suddenly drops to zero, and then starts increasing again usually indicates a process restart.
Most TiDB OOM errors stem from one or more of the following causes.
| Cause | What's happening | How it shows up | How often |
|---|---|---|---|
| Memory-heavy queries | Large intermediate result sets consume RAM | One query uses several GB | Most common |
| Too many concurrent sessions | Multiple queries collectively exceed available memory | Spikes during peak traffic | Common |
| Memory not being released | Memory gradually grows over time | Slow upward trend | Occasional |
| Under-provisioned deployment | Insufficient system RAM | OOM even under light load | Less common |
The first two causes are responsible for a large proportion of production OOM events.
Configuration changes can help, but they cannot completely protect a fundamentally expensive query. TiDB query optimization at the SQL level is often the real fix — the following patterns commonly appear in OOM post-mortems.
A HashJoin loads the inner side of the join into an in-memory hash table before it starts matching rows. If the inner table has millions of rows, a single query can consume several gigabytes of memory. Run EXPLAIN and look for a HashJoin with a very large estRows on the inner side. If you see it, consider hinting toward MergeJoin instead — it uses far less memory because it works with sorted streams rather than building a large in-memory hash table.
-- check what the planner chose
EXPLAIN SELECT * FROM orders JOIN order_items ON orders.id = order_items.order_id;
-- if HashJoin shows estRows in the millions on the inner side, that's the problem
-- nudge it toward a less memory-hungry join
SELECT /*+ MERGE_JOIN(orders, order_items) */
orders.id, order_items.quantity
FROM orders
JOIN order_items ON orders.id = order_items.order_id
WHERE orders.created_at > '2024-01-01';
Expert Tip: Spotting one bad HashJoin is easy. Finding every query in a busy cluster that's quietly doing this is a different problem entirely — it usually needs systematic plan review across your TiDB slow query log, not a one-off EXPLAIN. Mafiree's TiDB team does exactly this kind of audit if you'd rather not chase it query by query.
HashAgg is fast because it can process data in parallel, but each worker may maintain its own hash table. With a large number of distinct grouping values, memory usage can grow rapidly. StreamAgg processes rows in sorted order and generally uses less memory — a reasonable trade-off for memory-constrained workloads.
SELECT /*+ STREAM_AGG() */ region, SUM(revenue)
FROM sales
GROUP BY region;
If TiDB's statistics are outdated, the optimizer might estimate 1,000 rows for a scan that actually returns 10 million, and pick algorithms suited for a small dataset. Check the health of your statistics regularly, especially on tables that get a lot of writes:
SHOW STATS_HEALTHY;
-- for high-write tables, refresh statistics when necessary
ANALYZE TABLE orders;
ANALYZE TABLE order_items;
Stale statistics can lead to bad plans, and bad plans can directly contribute to excessive memory usage.
TiDB's transaction model caches all write operations in memory before commit. A transaction modifying millions of rows may consume two to three times — or potentially more — than the actual size of the data involved. Break large bulk operations into smaller batches, or look at the tidb_dml_type variable (set to "bulk") or non-transactional DML for cases that specifically need this.
-- instead of one giant delete:
-- DELETE FROM logs WHERE created_at < '2024-01-01';
-- loop this until affected rows = 0, sleep briefly between rounds
DELETE FROM logs
WHERE created_at < '2024-01-01'
LIMIT 10000;
TiDB memory protection works in layers — per-query limits, per-instance memory limits, and operating-system or cgroup limits. Each layer should be configured deliberately as part of any TiDB memory tuning strategy; relying on the defaults in production is risky.
The maximum memory a single SQL query can consume. Analytical queries may require more, but raise this carefully — multiple queries can consume memory concurrently.
What TiDB does when a query exceeds its memory quota. With CANCEL, TiDB terminates the query and returns an error — the right choice for production. LOG allows the query to continue while logging the event, which may be useful temporarily for investigation but is not recommended as a permanent production setting.
The total memory budget for the TiDB server process. The default 80% may be unsuitable when TiDB shares a server with other database services, monitoring agents, backup processes, or general operating-system workloads. In hybrid deployments, an explicit memory limit is strongly recommended.
Controls when TiDB generates memory usage warnings and starts collecting diagnostic information. Setting it to 0.7 gives you a chance to investigate before memory usage reaches a critical level.
TiDB supports spilling intermediate execution data to disk when memory pressure becomes high. Disk spill behavior is controlled by tidb_mem_quota_query, tidb_enable_tmp_storage_on_oom, tmp-storage-path, and tmp-storage-quota.
Disk spill support has expanded across TiDB versions — HashAgg spill support, in particular, has improved in newer releases. When running a modern TiDB version, verify the exact behavior for your release.
Recommended Practice: Configure a dedicated temporary storage path explicitly with tmp-storage-path. This provides additional protection against memory-heavy queries. However, disk spill should be treated as a safety mechanism, not a replacement for query optimization.
TiDB provides memory-related system tables for monitoring current and historical memory usage. To view current and historical memory usage, query:
INFORMATION_SCHEMA.MEMORY_USAGEINFORMATION_SCHEMA.CLUSTER_MEMORY_USAGEINFORMATION_SCHEMA.MEMORY_USAGE_OPS_HISTORYINFORMATION_SCHEMA.CLUSTER_MEMORY_USAGE_OPS_HISTORYThe OPS_HISTORY tables retain the latest 50 records per instance. These tables are useful for identifying which operations consumed memory and investigating OOM events after they occur.
Before putting a TiDB cluster into production, verify the following.
tidb_server_memory_limit explicitlytidb_mem_quota_query based on workloadtidb_mem_oom_action is set to CANCELtidb_memory_usage_alarm_ratio to an appropriate early-warning thresholdEXPLAIN ANALYZETiDB OOM errors are rarely random. They're the predictable result of specific SQL patterns, undersized memory limits, or configuration defaults that don't match your workload. Confirming whether the operating system or TiDB's own memory manager caused the event is the first step in troubleshooting any recurring OOM pattern — from there, tuning tidb_mem_quota_query and tidb_server_memory_limit for your hardware, applying targeted query optimization to the worst offenders, and enabling disk spill as a safety net will prevent most repeat incidents.
For TiDB out of memory issues you can't fully resolve in-house, Mafiree's TiDB performance tuning and consulting team can audit your configuration and query patterns before the next incident happens.
Need help with a TiDB OOM issue?
Mafiree's TiDB consulting and performance optimization team can help with root-cause audits, configuration and memory tuning, and 24×7 incident support.
Contact Mafiree →Miru IT Park, Vallankumaranvillai,
Nagercoil, Tamilnadu - 629 002.
Unit 303, Vanguard Rise,
5th Main, Konena Agrahara,
Old Airport Road, Bangalore - 560 017.
Call: +91 6383016411
Email: sales@mafiree.com