VPS Running Out of Memory? How to Set Up Swap Properly (and Fix the Real Cause)
If you've ever watched a $5 VPS grind to a halt — SSH freezing, MySQL silently restarting, WordPress throwing "Error establishing a database connection" for no obvious reason — there's a good chance you've met the Linux OOM killer. It's not a bug. It's the kernel doing exactly what it's designed to do: when RAM runs out and there's no swap to fall back on, it picks a process (usually the biggest one, which is often MySQL) and kills it outright to keep the rest of the system alive.
The fix that actually matters is making sure your VPS has enough RAM for what it's running. But a swap file is the cheap insurance policy that buys you breathing room — and takes about two minutes to set up.
Check whether this is actually your problem
Before doing anything, confirm the OOM killer has actually fired:
sudo dmesg | grep -i "killed process"
If that returns lines mentioning mysqld, php-fpm, or another service, you've found your culprit. Check your current swap situation:
free -h
If the Swap row shows 0 across the board, that's very often the whole problem on a small VPS — there's no shock absorber between "memory is tight" and "the kernel starts killing things."
How much swap does your VPS actually need?
This is where most guides give you one generic number. In practice, the right amount depends on how much RAM you're already paying for — which ties directly into the VPS sizes from our cloud cost breakdown:
| VPS RAM | Typical workload | Recommended swap |
|---|---|---|
| 1 GB (~$5/month tier) | Small WordPress or personal project | 2 GB |
| 2 GB (~$12/month tier) | WordPress business site, small Laravel app | 2 GB |
| 4 GB (~$18–24/month tier) | Laravel SaaS with a queue worker | 2–4 GB |
The pattern above 2 GB of RAM: swap stops scaling linearly with RAM. Its job is to absorb short spikes, not to be a full-time substitute for memory you don't have — a server that's regularly dipping deep into swap needs more RAM, not more swap. If you're hitting that point at the 1 GB or 2 GB tier from our cost guide, that's a real signal it's time to size up, not just add insurance.
Create the swap file
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
If fallocate fails with an error (this happens on some filesystems, notably Btrfs), use dd instead — slower, but it works everywhere:
sudo dd if=/dev/zero of=/swapfile bs=1M count=2048
Confirm it's active:
free -h
You should now see the swap total reflected. This alone won't survive a reboot yet — add it to /etc/fstab to make it permanent:
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
Tune swappiness — don't leave it at the default
Swappiness controls how eagerly the kernel reaches for swap versus RAM, on a scale of 0–100. Ubuntu's default is 60, which is tuned for a desktop, not a server running a database:
sudo sysctl vm.swappiness=10
Make it permanent:
echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf
A value of 10 tells the kernel to strongly prefer RAM and only reach for swap under real pressure — appropriate for a server where swap is meant as a safety net, not routine memory management. Going all the way to 0 is usually a step too far; it can make the kernel wait until the last possible moment to swap, which risks the exact OOM kill you're trying to prevent.
The MySQL setting that's usually the actual cause
Adding swap treats the symptom. On a small VPS, the underlying cause is almost always innodb_buffer_pool_size set too high for the box it's running on. Check the current value:
mysql -u root -p -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';"
A common mistake is leaving this at a value copied from a tutorial written for a much bigger server. As a starting point on a shared web+database VPS (not a dedicated database server), keep it well under half of total RAM — on a 1 GB VPS, 128–256 MB is more realistic than the "70% of RAM" advice you'll see aimed at dedicated database hosts. Set it in /etc/mysql/my.cnf:
[mysqld]
innodb_buffer_pool_size = 256M
Then restart MySQL:
sudo systemctl restart mysql
Optional: hard-limit a service so it can't take down the whole box
If one specific service (a runaway cron job, a leaky background worker) keeps being the trigger, you can cap it at the systemd level so it hits its own ceiling instead of the kernel picking a random victim:
sudo systemctl edit mysql
[Service]
MemoryMax=512M
This is especially worth pairing with a Supervisor-managed Laravel queue worker on a small VPS — a stuck or leaking job is a classic way a background process quietly eats all available memory over hours, and a memory cap turns "the whole server locks up" into "one service restarts cleanly."
Confirm it's actually working
Don't just trust the setup — watch it under real load:
watch -n 2 free -h
During normal traffic, available memory should stay comfortably above zero, and swap usage should stay low and stable rather than climbing steadily. If you're seeing swap fill up and stay full, that's the sign this VPS genuinely needs more RAM — swap bought you time to notice the problem calmly instead of finding out via a 3 AM downtime alert.
Commands and sizing guidance in this article reflect current Ubuntu/Debian practice as of August 2026.
Comments 0
Be the first to comment.
Leave a comment