it-operations
Tuning Linux Page Cache & InnoDB: Stop Database OOM Kills

On This Page (13 sections)
WSL2 eating all your RAM or choking on vmmem page caches? Generate a tuned .wslconfig with memory limits, swap caps, and automatic VHD shrinking in 30 seconds.
tune your setup with our WSL2 .wslconfig GeneratorDirect Answer (Preventing Database OOM Kills): To prevent silent Linux kernel Out-Of-Memory (OOM) kills on production MySQL and PostgreSQL database hosts, you must restrict the OS filesystem page cache from competing with user-space buffer pools. Rather than allocating 80% of physical RAM to the database engine, cap
innodb_buffer_pool_sizeat 65% to 70% of host memory to reserve essential headroom for kernel slab allocations, binary log buffers, and per-connection query threads. In/etc/sysctl.d/99-database-memory.conf, reducevm.swappinessto1or10to stop InnoDB buffer memory from paging out to disk, set explicit byte limits onvm.dirty_background_bytes(256MB) andvm.dirty_bytes(1GB) to ensure smooth background writeback, and raisevm.vfs_cache_pressureto150to reclaim unused filesystem dentries and inodes. Finally, configure database systemd units withOOMScoreAdjust=-900and enableO_DIRECTto eliminate redundant OS page caching.
When provisioning production database servers, the standard rule of thumb is straightforward: allocate 70% to 80% of total physical RAM to the innodb_buffer_pool_size (or PostgreSQL shared_buffers). Yet, in high-throughput production environments across our infrastructure workbench, systems with 128GB or 256GB of RAM frequently experience sudden, unexplainable query latency spikes, swap thrashing, or the dreaded Linux kernel Out-Of-Memory (oom-killer) terminating the mysqld or postgres process without warning.
The root cause rarely lies within the database engine itself. Instead, it stems from an unmanaged resource conflict between the Linux kernel page cache and the database buffer pool. Without proactive kernel virtual memory (vm) tuning, Linux will aggressively grow its file-backed page cache until kernel slab memory is exhausted, forcing emergency synchronous reclaim cycles that freeze transactional query threads.
Jump to a section:
- Anatomy of Kernel Database Memory Conflicts
- Diagnosing Kernel Memory Starvation
- Five Critical Sysctl Tweaks for DBAs
- Kernel Virtual Memory Tuning Matrix
- Storage Subsystem and Direct IO Tuning
- Protecting Database Daemons from OOM Kills
- Conclusion and Implementation Checklist
- Related Linux and Database Runbooks
Anatomy of Kernel Database Memory Conflicts
In a dedicated database server, physical host memory is partitioned across three competing consumers:
- Database Native Buffer Pool: The user-space allocation where InnoDB caches table data, secondary indexes, undo logs, and insert buffers (
innodb_buffer_pool_size). - Linux OS Page Cache: The kernel-level cache for filesystem blocks, binary logs, slow query logs, temporary disk tables, and general OS disk I/O.
- Transient Connection Allocations: Per-thread buffers including
sort_buffer_size,join_buffer_size,read_rnd_buffer_size, and temporary hash tables.
┌────────────────────────────────────────────────────────────────────────┐
│ TOTAL PHYSICAL HOST RAM (100%) │
├───────────────────────────────────────┬─────────────────┬──────────────┤
│ InnoDB Buffer Pool (User Space) │ Linux OS Cache │ Connection │
│ (70% - 75%) │ (15% - 20%) │ Buffers (5%) │
├───────────────────────────────────────┴─────────────────┴──────────────┤
│ ⚠️ DANGER: If OS Page Cache + Transient Buffers > Available Headroom, │
│ the Linux Kernel invokes oom-killer and terminates mysqld (PID). │
└────────────────────────────────────────────────────────────────────────┘
When an active database performs massive table scans or rotates multi-gigabyte binary logs, the kernel eagerly fills all remaining unallocated RAM with dirty file pages. Because Linux treats “free” memory as wasted memory, it will not proactively release page cache pages until the host hits the watermarks defined by vm.min_free_kbytes.
Under sudden transactional query bursts, the kernel fails to allocate memory fast enough, triggering the OOM killer. The Linux kernel scans process badness heuristics, identifies the database process as the largest anonymous RSS memory consumer, and issues SIGKILL.
Diagnosing Kernel Memory Starvation
Before modifying kernel parameters on our production clusters, our team captures real-time OS page cache and slab consumption using /proc/meminfo:
# Inspect total, active, and reclaimable slab allocations
cat /proc/meminfo | grep -E "MemTotal|MemFree|MemAvailable|Buffers|Cached|Slab|SReclaimable"
Next, verify how much memory is trapped inside the kernel’s directory entry (dentry) and inode caches:
# View real-time slab cache consumers sorted by size
slabtop -sc -o | head -n 15
If SReclaimable and Cached occupy more than 20% of your system RAM while MemAvailable is hovering below 5%, the kernel is failing to evict file cache aggressively enough to satisfy database engine allocations.
In MySQL, correlate this with internal buffer usage:
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_pages_dirty';
SHOW GLOBAL STATUS LIKE 'Innodb_buffer_pool_wait_free';
A non-zero value on Innodb_buffer_pool_wait_free indicates that transactional threads are stalling because InnoDB is waiting for clean pages to be flushed to disk, exacerbated by OS filesystem writeback backpressure.
Five Critical Sysctl Tweaks for DBAs
To establish predictable memory boundaries and eliminate OOM kills, apply these five virtual memory (sysctl) configurations in /etc/sysctl.d/99-database-memory.conf:
A. Adjusting vm.swappiness (Set to 1 or 10)
By default, standard Linux distributions ship with vm.swappiness = 60, which instructs the kernel to swap out anonymous memory (including active database threads) to keep the filesystem page cache warm. On database hosts, swapping causes catastrophic latency jitter.
Set swappiness to 1 (do not set to 0, which entirely disables swap and increases OOM risk):
sysctl -w vm.swappiness=1
B. Throttling Flush Watermarks (dirty_background_ratio & dirty_ratio)
Linux default dirty ratios are dangerously high for modern multi-gigabyte database servers (dirty_ratio = 20 and dirty_background_ratio = 10). On a 128GB machine, this allows 25GB of unwritten disk pages to accumulate in RAM before forcing background flushes, causing the kernel to pause I/O completely during writeback bursts.
Switch from percentage-based ratios to explicit byte limits:
# Wake up flusher threads when dirty pages exceed 256MB
sysctl -w vm.dirty_background_bytes=268435456
# Block writing processes when dirty pages exceed 1GB
sysctl -w vm.dirty_bytes=1073741824
C. Increasing vfs_cache_pressure (Set to 150)
The vfs_cache_pressure variable controls the tendency of the kernel to reclaim memory used for directory and inode caching relative to page cache and swap. Setting this to 150 prioritizes reclaiming inode metadata over paging out transactional memory:
sysctl -w vm.vfs_cache_pressure=150
D. Tuning System Memory Reclaim & Page Fragmentation
When running hybrid database development environments, containerized testing nodes, or production database instances inside cgroups, memory reclaim stalls can severely bottleneck local read/write execution loops. For an in-depth breakdown of how Linux cgroups and memory reclamation handle background allocations under continuous workloads, review our Linux kernel memory reclaim and vmmem buffer allocation guide.
E. Reserving Emergency Headroom (vm.min_free_kbytes)
Ensure the kernel always preserves emergency network and interrupt headroom so it can clean pages without stalling:
# Reserve approximately 1.5GB to 2GB for emergency kernel operations
sysctl -w vm.min_free_kbytes=2097152
Kernel Virtual Memory Tuning Matrix
| Parameter | Linux Default | Production Database Recommended | Impact on Database Engine |
|---|---|---|---|
vm.swappiness | 60 | 1 to 10 | Prevents InnoDB buffer pool memory from being swapped to disk. |
vm.dirty_background_bytes | Unset (10%) | 268435456 (256MB) | Initiates early, smooth background disk writeback. |
vm.dirty_bytes | Unset (20%) | 1073741824 (1GB) | Caps dirty cache to prevent sudden system-wide I/O lockups. |
vm.vfs_cache_pressure | 100 | 150 | Aggressively purges unused filesystem dentries and inodes. |
vm.min_free_kbytes | Auto (~67MB) | 1048576 to 2097152 | Provides headroom to prevent instant synchronous OOM kills. |
Storage Subsystem and Direct IO Tuning
Tuning OS memory works in tandem with database disk presentation. When the database engine writes transaction logs (WAL or binlogs) or flushes dirty buffer pool pages, bypass the OS page cache entirely by configuring Direct I/O.
In MySQL my.cnf:
[mysqld]
# Bypass OS Page Cache for data and log writes
innodb_flush_method = O_DIRECT
innodb_flush_neighbors = 0
In PostgreSQL postgresql.conf:
# Enforce immediate synchronization without dual-caching
wal_sync_method = fdatasync
synchronous_commit = on
When evaluating underlying storage performance, block sizes, and write amplification during database staging benchmarks, check our detailed engineering analysis on storage I/O throughput and developer filesystem benchmarks to quantify how filesystem filter drivers impact random 4KB database writes.
Protecting Database Daemons from OOM Kills
As a final fail-safe on our database instances, our team configures the Linux systemd service unit to decrease the likelihood of the OOM killer targeting the database daemon during unexpected host spikes.
Add an override configuration for MySQL:
mkdir -p /etc/systemd/system/mysql.service.d/
cat <<EOF > /etc/systemd/system/mysql.service.d/override.conf
[Service]
# Reduce OOM priority (-1000 completely disables OOM killing)
OOMScoreAdjust=-900
LimitMEMLOCK=infinity
EOF
systemctl daemon-reload
systemctl restart mysql
Verify that the process score has taken effect:
cat /proc/$(pgrep mysqld)/oom_score_adj
# Output should return -900
Conclusion and Implementation Checklist
Eliminating database memory stalls requires harmonizing the Linux virtual memory manager with the database’s native caching mechanisms. Before scaling up hardware or blaming query performance, ensure your host implements:
- Explicit buffer bounds: Reserve 20% of host RAM for the OS, transient connections, and kernel page caches.
- Deterministic writeback limits: Cap dirty page generation using
vm.dirty_background_bytesandvm.dirty_bytes. - Low swappiness (
1-10): Ensure the host never swaps out active InnoDB buffer pages. - Direct I/O (
O_DIRECT): Eliminate dual-caching between Linux and database engines. - OOM Protection: Configure
OOMScoreAdjust=-900on critical production database services.
Related Linux and Database Runbooks
Explore our workbench deep dives on kernel tuning, developer environments, and systems stability:
- Debloat Windows 11 Without Breaking WSL or Store: 2026 Sysadmin Guide — Prune consumer background daemons and protect developer virtualization services.
- Why WSL2 vmmem Won’t Free RAM: Auto Memory Reclaim Fix — Fix runaway Hyper-V and Linux container memory consumption.
- How to Run DeepSeek-R1 on 8GB VRAM: Local AI Benchmarks — Quantization, KV-cache tuning, and PCIe memory spillover prevention.
- Best Free VPNs in 2026: 5 Tested Safe & Unlimited Plans — WireGuard throughput, DNS leak testing, and remote dev connection security.
- Fix CLOCK_WATCHDOG_TIMEOUT (0x101) Blue Screen Error in Windows 11 — Triage hardware thread deadlocks and firmware voltage stability.
- Dev Drive ReFS vs NTFS Benchmarks for High I/O Stacks — Throughput and copy-on-write gains for local developer workflows.
- Fix nvlddmkm Event ID 13 GPU Driver Crashes in Windows 11 — TDR timeout recovery, DDU wipes, and PCIe power rail troubleshooting.
- How We Scaled E-Commerce Catalog Sync Across 35 Stores — Distributed queue tuning, memory caching, and low-latency inventory locks.
Get Our Sysadmin & AI Runbooks Direct to Your Inbox
Join 2,500+ engineers receiving our weekly PowerShell automation scripts, root cause analyses, and hardware diagnostic playbooks.
Frequently Asked Questions: Tuning Linux Page Cache & InnoDB: Stop Database OOM Kills
Why does the Linux OOM killer terminate MySQL or PostgreSQL?
How does the Linux page cache cause database memory starvation?
What should vm.swappiness be set to on a database server?
Why switch from dirty ratios to dirty bytes?
How does O_DIRECT prevent dual-caching?
Official Technical References
- Linux Kernel Documentation: Virtual Memory Sysctl — The Linux Kernel Organization
- MySQL 8.4 Reference Manual: InnoDB Buffer Pool Sizing — Oracle Corporation
- PostgreSQL 17 Documentation: Resource Consumption & Shared Buffers — PostgreSQL Global Development Group
Add PraveenTechWorld as a preferred source in your Google Search results.
Explore more: Browse all it operations guides or check related articles below.


