Fix Prometheus High Memory Usage and OOM Kills
The Error: Prometheus Killed by OOM
You check your monitoring server and find Prometheus has been killed:
dmesg | grep -i oom
[12345.678] Out of memory: Killed process 1234 (prometheus) total-vm:16524288kB
Or in journalctl:
prometheus.service: Main process exited, code=killed, status=9/KILL
Prometheus keeps all recently ingested data in memory. When it runs out, the kernel OOM killer steps in.
Root Cause
Prometheus memory usage is directly tied to the number of active time series. Each unique combination of metric name and label values is a separate series. Common causes of memory explosion:
- High cardinality labels like user IDs, request paths, or pod UIDs
- Too many targets being scraped simultaneously
- Long
--storage.tsdb.retention.timekeeping too much data on disk (and in memory during compaction) - Missing
sample_limitallowing targets to dump unlimited metrics
Step-by-Step Fix
1. Find Your Current Series Count
prometheus_tsdb_head_series
If this number is in the millions, you have a cardinality problem. A healthy Prometheus instance typically handles 1-2 million series per 8 GB of RAM.
2. Identify the Biggest Offenders
Find which jobs produce the most series:
topk(10, count by (job) ({__name__=~".+"}))
Find metrics with the most label combinations:
topk(10, count by (__name__) ({__name__=~".+"}))
3. Drop High-Cardinality Metrics
Add metric_relabel_configs to your prometheus.yml:
scrape_configs:
- job_name: 'my-app'
metric_relabel_configs:
# Drop metrics with high-cardinality labels
- source_labels: [__name__]
regex: 'http_request_duration_bucket'
action: drop
# Remove a specific high-cardinality label
- regex: 'instance_id'
action: labeldrop
4. Set Sample Limits per Target
Protect Prometheus from misbehaving targets:
scrape_configs:
- job_name: 'my-app'
sample_limit: 10000
static_configs:
- targets: ['app:8080']
If a target returns more than 10,000 samples, the entire scrape is rejected and you'll see a clear error instead of an OOM.
5. Tune Storage Flags
Start Prometheus with memory-conscious flags:
prometheus \
--storage.tsdb.retention.time=15d \
--storage.tsdb.retention.size=30GB \
--storage.tsdb.wal-compression \
--query.max-samples=50000000
Reducing retention from 30 days to 15 days can cut memory usage significantly during compaction cycles.
6. Restart and Monitor
sudo systemctl restart prometheus
# Watch memory usage
watch -n 5 'ps -o pid,rss,comm -p $(pidof prometheus) | awk "{print \$2/1024 \" MB\"}"'
7. Verify Series Count is Dropping
After config reload, check that series count decreases over the next few scrape cycles:
rate(prometheus_tsdb_head_series_created_total[5m])
Prevention Tips
- Set
sample_limiton every scrape job. This is your safety net against cardinality bombs. - Alert on series count:
prometheus_tsdb_head_series > 2000000should page someone. - Use recording rules instead of expensive queries that force Prometheus to hold more data in memory.
- Move long-term storage to Thanos or Cortex and keep Prometheus retention at 2-7 days.
- Review new metrics in code review. A label with unbounded values is a production incident waiting to happen.
Was this article helpful?
CI/CD Engineering Lead
Automation evangelist who believes no deployment should require a human. I write pipelines, break pipelines, and write about both. Code-first, always.
Related Articles
Prometheus Target Down Error: Debugging Failed Scrapes And Network Connectivity Issues
You've deployed Prometheus, configured your targets, and everything looks perfect in your YAML files. Then you check the Prometheus UI and see those dreade...
Fix Prometheus 'context deadline exceeded' Scrape Errors
Resolve Prometheus 'context deadline exceeded' errors caused by slow scrape targets, network issues, or misconfigured timeouts with this step-by-step fix guide.
Prometheus Federation: Scraping Metrics Across Multiple Data Centers With A Global View
If you're running Kubernetes clusters across multiple data centers or cloud regions, you've probably felt the pain of fragmented observability. Each cluste...
Prometheus Remote Write Tuning For High-Throughput Long-Term Storage With Thanos
If you're running Prometheus at scale with Thanos for long-term storage, misconfigured remote write settings are silently killing your performance — and yo...
Prometheus Recording Rules For High-Cardinality Metric Aggregation
If you've been running Prometheus in production for more than a few months, you've probably hit the wall. Dashboards that take 30 seconds to load. Alerts t...
Prometheus Alerting Rules: From Noisy to Actionable
Write Prometheus alerting rules that page on real problems, not noise — with practical PromQL, severity levels, and runbook patterns.
More in Prometheus
View all →Prometheus Service Discovery in Kubernetes: Auto-Scrape Everything
Configure Prometheus Kubernetes service discovery to automatically scrape pods, services, and nodes — no manual target management.
PromQL Queries You'll Actually Use in Production
A practical PromQL reference covering request rates, latency percentiles, resource usage, and Kubernetes workload queries for real production dashboards.