RAM Headroom on a VPS: How Much Spare Memory You Should Actually Keep

A VPS running at 95% memory utilization is not efficient — it is one traffic spike away from thrashing. Linux reports “available” memory separately from “free” memory precisely because page cache is reclaimable and application allocations are not. The number to watch is available memory, and the headroom you should keep depends on how fast your workload can grow.

Workload typeBurst multiplierTarget headroomOn a 2 GB plan, keep free
Static site behind a CDN1.2×20%400 MB
WordPress with page cache1.5–2×35%700 MB
WordPress without cache2–3×40%800 MB
Custom app with uncached queries3×+50%1 GB
Database server1.3×25%500 MB

Read the Right Column

free -m shows a free column that is usually near zero on a healthy server, because Linux uses spare RAM for page cache. That is not a problem. The column that matters is available, which discounts reclaimable cache and estimates what a new application allocation could get without swapping.

free -m
#               total        used        free      shared  buff/cache   available
# Mem:           1987         842          91           8        1054         986
#
# 986 MB available, 1054 MB in reclaimable cache -> healthy.

# Look at it as a percentage
free -m | awk 'NR==2{printf "%.1f%% available\n", $7/$2*100}'

As a rule of thumb, treat under 15% available as a warning and under 8% as an active incident. Below 8%, the kernel starts reclaiming aggressively, then swapping, and swap on a budget plan is typically slow shared storage — latency jumps before you see an out-of-memory kill.

The Two Metrics That Predict Trouble

Absolute headroom tells you where you are. These two tell you where you are going:

  • Swap in/out rate (vmstat columns si/so): any sustained non-zero value means the working set no longer fits. Intermittent single-digit KB pages are normal noise; sustained hundreds of KB/s is not.
  • Page-scan rate (sar -B pgscan): rising scans with flat application memory means the kernel is hunting for free pages. That is the last warning before swap.
vmstat 5 12 | awk 'NR>2{print "avail-ish used:",$4" si:",$7" so:",$8}'

# Which process is actually growing
ps -eo rss,comm --sort=-rss | head -8

# Per-process growth over 60s
for i in 1 2 3; do ps -eo rss,comm --sort=-rss | head -4; sleep 20; done

Where Headroom Disappears

CauseSymptomFix
PHP-FPM pool sized too largeMany idle workers, each holding 40–60 MBCut pm.max_children to fit measured concurrency
MySQL buffer pool too generousDatabase RSS grows to the configured capSet innodb_buffer_pool_size to ~50% of RAM on a shared box
Docker image layer cacheSlow, steady growth after each deployPrune images on a schedule
Unbounded log buffers with journaldGrowth after incidentsSet SystemMaxUse
Memory leak in an app workerRSS climbs monotonically over daysRestart worker on a timer, then fix the leak

If two or more of these stack up, no amount of tuning recovers the headroom. That is the point where the RAM tier itself is the problem. Our VPS plan comparison table shows what each successive RAM tier costs per month, which makes the “tune vs. upgrade” decision a straight arithmetic comparison rather than a guess.

Right-Sizing the Two Processes That Eat Headroom

On a typical budget VPS, PHP-FPM and MySQL account for most of the working set, and both ship with defaults that assume more RAM than you have. The failure mode is not a crash — it is a slow bleed of available memory as workers accumulate.

SurfaceCommon defaultBudget-safe settingHeadroom recovered
PHP-FPM pm.max_children25 on a 2 GB box8–10 (measured concurrency)600–900 MB
MySQL innodb_buffer_pool_size128 MB (too small) or 70% of RAM (too large)40–50% of installed RAM200–400 MB
Redis maxmemoryunboundedmemory limit + allkeys-lruprevents unbounded growth
journald SystemMaxUse10% of filesystem200–400 MBdisk, plus predictable logs

Note the asymmetry in the MySQL row. Setting the buffer pool too small causes steady disk reads and higher latency; setting it too large removes the headroom that the web tier needs during bursts. On a single 2 GB server running both, 512 MB is a reliable compromise. On a 4 GB server that also runs the web tier, 1.5–2 GB is comfortable.

# How much memory PHP-FPM is really holding
ps -eo rss,cmd | grep 'php-fpm: pool' | awk '{s+=$1; n++} END{printf "%d workers, %.0f MB total, %.0f MB each\n", n, s/1024, s/1024/n}'

# MySQL resident size vs configured pool
ps -o rss= -C mysqld | awk '{printf "mysqld RSS: %.0f MB\n", $1/1024}'
mysql -e "SHOW VARIABLES LIKE 'innodb_buffer_pool_size';"

Run this under peak load, not at 3 AM. If PHP-FPM workers total more than 40% of installed RAM, the pool is over-provisioned regardless of what setting is in the config file.

How to Set a Headroom Alarm

Alert on available memory, not on usage, and alert on the trend rather than the instantaneous value. A useful threshold set:

  • Warning: available drops below 20% for more than 10 minutes
  • Critical: available below 10%, or any sustained so above 100 KB/s
  • Trend: 7-day peak available memory declines more than 25% week over week

Free tooling covers all three; our list of free monitoring tools for budget VPS servers includes the ones that graph available memory without a paid agent.

When you do upgrade, buy the next tier up rather than the next tier that exactly fits — headroom is the product you are actually paying for. InterServer holds pricing flat across the term so the upgrade math stays stable: view InterServer VPS tiers. If you would rather find the exact threshold empirically, Vultr lets you resize hourly and watch the headroom curve move in real time.

Affordable-Vps-Server-Author
Affordable-Vps-Server-Author
Articles: 290

Leave a Reply