When a VPS goes slow, the temptation is to resize it. Resist that until you know what is actually consuming the machine - a runaway process on a larger server is simply a more expensive runaway process. This guide gives you a diagnostic order, the commands that answer each question, and how to tell a genuine capacity problem from a fixable one.
uptime # how loaded, and for how long
free -h # is memory exhausted, is it swapping
df -h # is a disk full
top -o %CPU # what is actually running
Reading load average
uptime gives three load figures - the average over 1, 5 and 15 minutes.
The number to compare against is your core count, which you can confirm with nproc. On a 4-core VPS 4 (4 vCores), a load of 4.0 means the CPU is fully committed with nothing queuing.
| Load vs cores | Meaning |
|---|---|
| Below core count | Healthy, with headroom. |
| Around core count | Fully used. Fine briefly, a concern if sustained. |
| Well above core count | Work is queuing. Everything feels slow. |
| 1-minute high, 15-minute low | A spike just started. Find it now, while it is still running. |
| 15-minute high too | Sustained. This is either real growth or something stuck. |
iotop and the wa (I/O wait) figure in top, not at core count.Memory, and the swap trap
free -h
Read the available column, not free. Linux deliberately uses spare memory for disk cache, so a healthy server shows very little "free" - that is the memory doing useful work, and it is released on demand.
What matters is the swap line. Sustained swapping is the single most common cause of a VPS that feels dramatically slower than its specification suggests: the machine is moving memory to disk and back, and every operation waits on it.
# What is using the most memory?
ps aux --sort=-%mem | head -10
If the answer is your database or PHP-FPM, it is usually a tuning problem before it is a sizing problem - too many workers configured, or a query loading far more rows than it needs.
Disk space and inodes
df -h # space
df -i # inodes - can run out even with space free
du -sh /* 2>/dev/null | sort -h
du -sh /var/log/* | sort -h
A full disk breaks things in confusing ways: databases refuse writes, sessions fail, logs stop. Check it early, because the symptoms rarely point at the cause.
The usual culprits are runaway logs, old backup archives, and package caches. Fix a log that is growing without limit rather than just deleting it - journalctl --vacuum-size=200M and a working logrotate configuration stop it recurring.
Finding the process responsible
top -o %CPU # sort by CPU, press M to sort by memory
ps aux --sort=-%cpu | head -10
sudo iotop -o # only processes doing disk I/O
ss -tulpn # what is listening, and what is connected
htop is worth installing for an easier view. If a single process is pinned at 100% for minutes at a time, that is your answer - note its command line before you kill it, so you can work out why.
Is it traffic, or is it you?
Before concluding you have outgrown the plan, check whether the load matches real visitors:
# Requests per hour today
awk '{print $4}' /var/log/nginx/access.log | cut -d: -f1-2 | uniq -c | tail -20
# Top client addresses
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10
# Slowest / most requested paths
awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10
A single address making thousands of requests is a scraper, not growth - block it at the firewall. Load that spikes at exactly the same minute each hour is a cron job, not visitors.
Checking your own scheduled jobs
crontab -l # your user
sudo crontab -l # root
systemctl list-timers --all
Overlapping cron runs are a classic cause of creeping load: a job that takes longer than its interval accumulates copies until the server is doing nothing else.
Reading the logs
journalctl -p err --since today # errors today
journalctl -u nginx --since "1 hour ago"
sudo dmesg -T | tail -40 # kernel messages, OOM kills
sudo grep -i "out of memory" /var/log/syslog
dmesg -T | grep -i oom shows it plainly, and the fix is tuning or more memory, not restarting the service on a schedule.When to resize, and when not to
| Evidence | Action |
|---|---|
| Sustained load above cores, spread across many legitimate processes, at genuine traffic | Resize. You have outgrown the plan. |
| Constant swapping with memory genuinely in use | Resize memory - after checking worker counts are sane. |
| One process pinned at 100% | Fix that process. A bigger server will not. |
| Load spikes hourly | A cron job. Reduce frequency or move it off peak. |
| One IP address dominating the access log | Block it. Do not pay for a scraper's traffic. |
| Load appeared with no traffic change and no deploy | Check for compromise before anything else - unfamiliar processes, outbound connections, unexpected logins. |
Resizing is quick when it is genuinely the answer: CPU and memory scale from the panel with a short reboot, and billing follows hourly.
Monitoring before it goes wrong
- Set up alerts so you hear about disk and memory before customers do. On an unmanaged VPS nothing watches the server unless you arrange it - the managed monitoring add-on is one option, an external uptime service is another.
- Watch disk growth, not just current usage. Steady growth has a deadline attached.
- Record a baseline. Note normal load, memory and disk when things are healthy. "Is this high?" is unanswerable without it.
- Keep logrotate working, so logs never become the emergency.
Frequently asked questions
What load average is too high?
There is no universal number - compare against your core count. Sustained load meaningfully above nproc means work is queuing.
My server shows almost no free memory. Is that bad?
Usually not. Linux uses spare memory as cache and frees it on demand. Read the available column, and worry about swap activity rather than "free".
Can Fast Hive tell me what is using my VPS?
Our engineers can confirm the hypervisor, network and storage beneath your server are healthy, which rules out a whole class of causes. What runs inside the server is visible to you via the commands above - and we will happily help you interpret what you find.
Is high I/O wait my fault or the platform's?
Fast Hive VPS storage is dedicated NVMe, so sustained I/O wait is nearly always your own workload - unindexed queries, or a process reading many small files. Open a ticket if you suspect otherwise; we can check the storage layer.
Should I add swap?
A small swap file prevents the OOM killer from terminating your database during a brief spike. It is a safety margin, not a substitute for adequate memory - a server that swaps constantly needs more RAM.
How do I see historical usage rather than right now?
Install a lightweight collector such as sysstat, which records metrics on a schedule so you can look back at when a problem started. Set this up before you need it.
uptime, free -h, df -h and top. Those four outputs let us rule the platform in or out immediately. Engineers are on call 24/7.