At a glance
The proportion of ClickHouse’s configured memory ceiling that is currently in use, as a percentage. It is computed from the liveMemoryTrackingmetric (the total RAM ClickHouse believes it is using across all queries, caches, and background work) divided bymax_server_memory_usage(the ceiling it will not knowingly cross). This is your real-time headroom gauge: how close is the whole instance to the wall? When this climbs and stays high, the next heavy query is at risk of being killed for memory, and the entire instance is one badGROUP BYaway from instability.
Calculation
The engine reads the live tracked-memory metric and the configured ceiling, then divides:MemoryTracking in system.metrics is ClickHouse’s authoritative count of currently allocated, tracked bytes. max_server_memory_usage is the hard ceiling above which ClickHouse refuses new allocations and begins aborting queries with MEMORY_LIMIT_EXCEEDED.
When max_server_memory_usage is 0 (the common “let ClickHouse decide” setting), the real ceiling is physical_RAM x max_server_memory_usage_to_ram_ratio (default ratio 0.9). In that case the engine substitutes the derived effective limit:
0. On a cluster, the card reports per node (the metric is node-local); the headline shows the busiest node so the gauge reflects the most at-risk member.
Worked example
A platform team runs ClickHouse on a 64 GB box withmax_server_memory_usage set to ~52 GB (the 0.8 ratio). The card normally sits around 35 to 45% during business hours. Snapshot taken on 03 Jun 26 at 14:20 UTC.
The gauge has climbed to 88% and held there for 12 minutes (amber/red). The team drills in and correlates with system.processes:
What the team reads:
- One query is eating the headroom. Of the 45.8 GB tracked, a single 18.2 GB
JOINaccounts for ~40% of the live total. The other 8 queries share the rest plus the caches. With only ~6 GB of slack left, the next concurrent heavy query will push past 52 GB and get killed at code 241, and on a server-wide breach that kill can land on an innocent query, not the greedy one. - This is a “before the kill” warning, by design. The Alert threshold fired at 85% so the team is looking before any
MEMORY_LIMIT_EXCEEDEDhas happened. The companion card MEMORY_LIMIT_EXCEEDED (24h) still reads0, which is exactly the state you want to act in. - Caches are part of the number, but not the villain here. The mark and uncompressed caches count toward
MemoryTracking, so a chronically high baseline can be cache-driven and harmless. But an 88% reading driven by a single live 18 GBJOINis query-driven and acute, not a cache baseline.
JOIN (add a WHERE filter or a LIMIT, or rewrite it to stream), cap the offending user with max_memory_usage_for_user, and if the baseline is persistently high, trim mark_cache_size / uncompressed_cache_size or scale the box. The gauge falls back into the green band once the heavy query completes and the headroom returns.
Sibling cards platform teams should reference together
Reconciling against the source
Where to look in ClickHouse itself:Why our number may legitimately differ from a manual read:SELECT value FROM system.metrics WHERE metric = 'MemoryTracking'for the live tracked-bytes numerator (useformatReadableSize(value)to make it human-readable).SELECT * FROM system.settings WHERE name IN ('max_server_memory_usage','max_server_memory_usage_to_ram_ratio')for the ceiling that forms the denominator.SELECT query, formatReadableSize(memory_usage) FROM system.processes ORDER BY memory_usage DESCto see which live queries are holding the memory right now.system.asynchronous_metrics(OSMemoryTotal,MemoryResident) for the OS-level view, to compare ClickHouse’s tracked figure against the process RSS. ClickHouse Cloud: the service monitoring view exposes memory utilisation against the service tier’s allocated ceiling.
Cross-connector reconciliation:
Known limitations / FAQs
Why does the card not match whattop shows for the clickhouse process?
Because the card uses MemoryTracking, ClickHouse’s own internal accounting of allocated bytes, not the OS resident set size (RSS). They are usually close but rarely identical: the allocator can hold freed pages that ClickHouse no longer counts but the OS still attributes to the process, and some allocations are untracked. MemoryTracking is the right number for “how close am I to the ceiling ClickHouse will enforce”, which is what the gauge is for.
My baseline sits at 60% even when idle. Is that a problem?
Not necessarily. The mark cache, uncompressed cache, and in-memory primary-key indexes all count toward MemoryTracking and persist between queries. A high but stable idle baseline is usually cache, which is doing its job. The risk is when live query memory stacks on top of that baseline and pushes you toward the ceiling. If the idle baseline is uncomfortably high, trim mark_cache_size / uncompressed_cache_size, accepting slightly lower cache hit rates in exchange for headroom.
What is the right action when the card is red?
Find the heavy live queries first: SELECT query, formatReadableSize(memory_usage) FROM system.processes ORDER BY memory_usage DESC. If one or two queries dominate, the fix is those queries (add filters, a LIMIT, or spilling via max_bytes_before_external_group_by) or capping the user. If many small queries add up, the issue is concurrency, and limiting concurrent queries or scaling the box is the answer. Acting while the card is red but MEMORY_LIMIT_EXCEEDED (24h) is still 0 prevents the kills entirely.
Why is 85% the threshold and not 95%?
Because ClickHouse memory can climb fast under concurrent load, and you want to be warned before the next heavy query tips the server-wide ceiling, not after. At 85% there is typically enough headroom to investigate and act before a kill. Pushing the threshold to 95% leaves almost no reaction time. This is an Alert Rules card with a per-profile threshold, so teams with very stable, predictable workloads can raise it, but the conservative default is intentional.
My max_server_memory_usage is 0. What is the gauge dividing by?
The derived effective ceiling: physical RAM multiplied by max_server_memory_usage_to_ram_ratio (default 0.9). A literal 0 means “unbounded by an explicit setting”, but ClickHouse still enforces the RAM-ratio limit, so the card uses that real ceiling as the denominator. The percentage therefore stays meaningful even with the explicit setting at 0.
Does background work (merges, mutations) count toward this number?
Yes. Merge and mutation buffers are tracked memory and count against max_server_memory_usage. During a merge storm you can see the gauge rise from background work alone. Pair with Merges In Progress: if memory is high and many merges are running, the contention is between background maintenance and live queries, and throttling merge concurrency or pausing heavy ingest can free headroom.
On a multi-node cluster, whose memory does the headline show?
The busiest node. Memory tracking is per node, and a cluster is only as safe as its most-pressured member, so the headline reflects the highest node rather than an average that would hide a single hot node. Drill in to see the per-node breakdown.