Recommended Services
Supported Scripts
Linux OOM killer troubleshooting guide for out-of-memory server crashes

You wake up to find MySQL has stopped, a site is down, and there is nothing useful in the application logs. The service just vanished. On a Linux server this is the classic fingerprint of the Linux OOM killer (out-of-memory killer), a kernel mechanism that terminates processes when the system runs out of memory. It protects the server from a total freeze, but it often kills the most important process on the box. This guide shows how to confirm an OOM event, find what caused it and make sure it does not happen again.

What the OOM Killer Does

Linux lets processes allocate more memory than physically exists (overcommit), betting that not all of it will be used at once. When actual demand outpaces RAM plus swap and the kernel cannot reclaim cache, it picks a victim based on an oom_score, which favours processes using a lot of memory that are not essential, and sends it SIGKILL. Because a database often holds the largest memory footprint, it is a frequent victim.

Because SIGKILL cannot be caught, the application writes nothing to its own log. That is why the evidence is in the kernel log.

Step 1: Confirm It Was the Linux OOM Killer

# Kernel ring buffer with readable timestamps
dmesg -T | grep -iE "out of memory|killed process|oom-kill"

# systemd journal (persists across reboots if configured)
journalctl -k --since "yesterday" | grep -iE "oom|killed process"

# Classic log files
grep -iE "out of memory|killed process" /var/log/messages /var/log/syslog 2>/dev/null

A typical entry looks like this:

Out of memory: Killed process 2314 (mysqld) total-vm:4864120kB, anon-rss:2951000kB, file-rss:0kB, shmem-rss:0kB, UID:27

Read it as: the process name, how much memory it used (anon-rss is the real resident usage) and which user it ran as. Just above the kill line the kernel prints a table of every process and its memory, which shows who was competing.

On systemd servers you may also see systemd-oomd or earlyoom acting before the kernel does.

Step 2: Find Out Who Was Using the Memory

Check the current state:

free -h
vmstat 1 5
# Top memory consumers
ps -eo pid,user,%mem,rss,cmd --sort=-rss | head -15

For shared-memory-aware numbers, smem -tk gives proportional set size (PSS), which is more honest than RSS when many PHP-FPM or Apache workers share pages. For history, install sar and review past memory use; see Install and Use SAR on Linux.

Typical causes on hosting servers

CauseWhy it exhausts memory
Too many PHP-FPM or Apache workerspm.max_children multiplied by memory per worker exceeds RAM
Oversized MySQL buffersinnodb_buffer_pool_size plus per-connection buffers times connections
Traffic spike or bot crawlHundreds of simultaneous dynamic requests
Memory leakA long-running script or a misbehaving plugin
No swapNothing absorbs a short burst
Backup, malware scan or cron job running at peakTemporary but heavy
Containers/VMs without limitsOne tenant starves the rest

Step 3: Do the Memory Maths

For web servers, the most common fix is simply sizing worker counts to the hardware. Measure the memory of one worker:

ps --no-headers -o rss -C php-fpm | awk '{s+=$1;n++} END {print s/n/1024 " MB average over " n " workers"}'

If workers average 80 MB and you have 4 GB of RAM with about 1.5 GB reserved for MySQL and the OS, you can safely run about (4096 - 1536) / 80 = 32 workers, so set pm.max_children = 30, not 200. The same logic applies to Apache’s MaxRequestWorkers.

For the database side, see our MySQL and MariaDB performance tuning guide: the worst-case MySQL memory is the buffer pool plus max_connections times the per-thread buffers.

Step 4: Add and Tune Swap

Swap is not a substitute for RAM, but a small amount lets the kernel evict idle pages instead of killing a process during a spike. Check it:

swapon --show
free -h

Create a 2 GB swap file if there is none:

fallocate -l 2G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab

Tune how eagerly the kernel swaps. The default vm.swappiness=60 is fine for general servers; many database servers prefer a lower value such as 10:

sysctl vm.swappiness=10
echo 'vm.swappiness=10' > /etc/sysctl.d/99-swappiness.conf

If vmstat shows constant si/so activity (swap in and out), the server is thrashing: it needs more RAM or fewer workers, not more swap. Note that KVM and dedicated servers allow swap freely, while some container-based VPS platforms do not; compare them in KVM vs OpenVZ vs LXC vs Docker.

Step 5: Protect Critical Services

You can tell the kernel which processes to avoid killing by adjusting oom_score_adj (from -1000, never kill, to +1000, kill first). With systemd:

# systemctl edit mariadb
[Service]
OOMScoreAdjust=-500

Then systemctl daemon-reload && systemctl restart mariadb. Use this sparingly. If everything is protected, the kernel will kill something worse. A better approach is to make the sacrificial process more killable, such as backup jobs or PHP workers:

# systemctl edit php-fpm
[Service]
OOMScoreAdjust=300

Also set a memory limit on a service so only it is affected rather than the whole system:

[Service]
MemoryMax=2G
MemoryHigh=1800M

Step 6: Stop Misbehaving Sites and Requests

Step 7: Monitor So You See It Coming

Set an alert at 85% memory use and alert on any oom-kill line. A tiny script from cron is enough:

#!/bin/bash
if dmesg -T | grep -q "Out of memory" ; then
  dmesg -T | grep -i "killed process" | tail -3 | mail -s "OOM on $(hostname)" admin@example.com
fi

For continuous visibility use Netdata, Prometheus with node_exporter, or Zabbix. See also How to Diagnose and Fix High CPU or Memory Usage on a Linux VPS.

When You Simply Need More RAM

If you have right-sized workers, tuned MySQL and the server still reaches its limits at normal traffic levels, it is outgrown. Upgrading RAM is cheaper than debugging recurring outages.

OOM Quick Reference

GoalCommand
Find OOM events`dmesg -T \grep -i “killed process”`
Memory overviewfree -h and vmstat 1 5
Top consumers`ps -eo pid,user,%mem,rss,cmd –sort=-rss \head`
Check swapswapon --show
Protect a serviceOOMScoreAdjust=-500 in systemd unit
Cap a serviceMemoryMax=2G

Frequently Asked Questions

How do I know if the OOM killer killed my process?

Search the kernel log with dmesg -T | grep -i "killed process" or journalctl -k. The application’s own log usually shows nothing, because SIGKILL cannot be handled.

Is swap a good idea on a web server?

A modest amount of swap is useful as a safety buffer. Constant swapping signals too little RAM or too many workers, not a need for more swap.

Can I disable the OOM killer?

You can set vm.panic_on_oom or disable overcommit, but this usually makes things worse, as the server may panic or refuse allocations. Fix the memory demand instead.

Why did the OOM killer choose MySQL?

The kernel scores processes mainly by memory use. A database with a large buffer pool is typically the biggest process, so it scores highest even though it is the most important.

Leave a Reply

Your email address will not be published. Required fields are marked *