Troubleshooting

Fix out-of-memory kills: the Linux OOM killer explained

Recognise when the Linux OOM killer stopped MySQL, PHP or Node.js, find which process used the memory, and prevent it with right-sized limits, swap and service settings.

IntermediateLinux VPS3 min read

When a server runs out of RAM and swap, the kernel's OOM killer picks a process and kills it to keep the system alive. Often the victim is the largest process, MySQL, which looks like a random database crash. This guide shows how to confirm an out-of-memory kill and stop it from recurring.

Before you start

  • Root access to the VPS.
  • The approximate time when a service stopped or a site went down.

Confirm an OOM kill

dmesg -T | grep -iE 'out of memory|killed process'
journalctl -k --since "2 days ago" | grep -i oom

A typical line:

Out of memory: Killed process 1234 (mysqld) total-vm:3800000kB, anon-rss:2100000kB

The anon-rss value is the memory that process really used. Services managed by systemd also show status=9/KILL or oom-kill in systemctl status.

Find out what used the memory

The killed process is not always the culprit. The kernel log prints a table of processes at the moment of the kill; look for many copies of the same program (dozens of php-fpm or node workers) or one process with a huge RSS. Right now:

ps aux --sort=-rss | head -15
free -h

Group memory per program to spot worker pools:

ps -eo rss,comm --no-headers | awk '{m[$2]+=$1} END {for (p in m) printf "%8.0f MB %s\n", m[p]/1024, p}' | sort -nr | head

Common causes and fixes

CauseFix
Too many PHP-FPM workersLower pm.max_children to fit RAM
MySQL buffer pool too largeReduce innodb_buffer_pool_size and max_connections
Node.js memory leakFix the leak; meanwhile PM2 max_memory_restart
Traffic spike or bot floodRate limiting, caching, blocking abusive IPs
Backups or imports at peak timeSchedule at night, lower priority
No swap at allAdd a small swap file as a cushion
Plan simply too smallUpgrade RAM

Budget memory per service

Add up the worst case: MySQL buffer pool plus per-connection buffers, PHP-FPM max_children × average worker size, Redis maxmemory, Node processes and the OS (300–500 MB). Keep the total below physical RAM, with swap only as a safety net.

Protect important services

  • Make the OOM killer prefer other processes by giving a service a lower score, e.g. for MySQL with systemctl edit mysql:
    [Service]
    OOMScoreAdjust=-500
  • Cap noisy services instead, so they cannot take the whole server:
    [Service]
    MemoryMax=1G
  • Ensure services restart automatically: Restart=on-failure.

Lowering a score only moves the problem to another process; the real fix is reducing total memory use.

Check the result

  • Watch free -h and vmstat 5 during busy hours: available memory should stay comfortably above zero.
  • Set up memory alerts (Netdata or another monitor) so you hear about pressure before the next kill.

Troubleshooting

  • Kills in a container or VPS but plenty of free RAM shown: a cgroup limit (Docker mem_limit, systemd MemoryMax, or the VPS plan limit) was reached, not host RAM.
  • Server freezes instead of killing: heavy swapping (thrashing). Reduce memory use or swappiness.
  • Cannot allocate memory when starting programs: the same root cause; free memory first.

OOM killer FAQ

Should I disable the OOM killer?

No. Without it the whole server can hang. Fix memory usage instead.

Does swap prevent OOM kills?

It delays them and absorbs short spikes; it does not fix sustained over-use.

Can this happen on cPanel hosting?

On shared hosting, CloudLinux enforces per-account memory limits instead, which shows as resource limit errors.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.