The server is slow: 10 Linux commands to run before you panic

Semih5 min read

Ten commands that tell you within five minutes whether a slow Linux server is short on CPU, memory, disk or network, or whether the application is to blame.

The phone rings: “The site is really slow.” The first reflex is to reboot the server, and I’ll admit it often works. But a reboot doesn’t fix the problem, it just wipes the evidence. Half an hour later the same phone rings again.

These are the 10 commands I run, in order, on a slow server. The goal isn’t to fix the problem right away but to find out where it is first. Server slowness has four usual suspects: CPU, memory, disk and network. The fifth is usually the application itself.

Short answer: check the load with uptime, CPU and wait times with top, memory with free and vmstat, disk with df and iostat, connections with ss, errors with journalctl and dmesg. Then move on to the application’s own logs.

1. uptime: how loaded are we?

uptime
nproc

The three numbers at the end are the load averages for the last 1, 5 and 15 minutes. Compare them with the core count (nproc). On a 4-core server, around 4 means “busy but coping”; 12 means “the queue is out the door”. Their order tells a story too: if the 1-minute value is far above the 15-minute one, the trouble has just started.

One Linux subtlety: the load average also counts processes waiting on disk. High load with an idle CPU usually points at the disk.

2. top (or htop): who’s eating it?

When top opens, look at three values in the %Cpu(s) line at the top:

  • us: CPU spent by applications. High means PHP, Node or the database is working hard.
  • wa: time spent waiting on disk. High means the disk, not the CPU, can’t keep up.
  • st: “steal”, the CPU that other tenants take from you on a virtual server. If it stays high, you have a neighbour problem, not a code problem. Time to talk to your provider.

Inside top, P sorts by CPU and M by memory.

3. free -h: is memory really gone?

free -h

The classic misreading: the free column looks tiny and people panic. Linux uses idle memory as disk cache and hands it back when needed. The column to read is available. If that’s small too and swap is filling, memory really is tight.

4. vmstat: memory and disk pulse

vmstat 1 5

Once a second, five lines. The si and so columns are reads from and writes to swap. If they stay above zero, the server is spilling to disk because RAM ran out, and everything crawls. The r column counts processes waiting for the CPU; if it keeps exceeding the core count, the CPU isn’t enough.

5. df: is the disk full?

df -h
df -i

When the disk hits 100%, the database can’t write, sessions can’t start, logs get cut off and the site breaks in very strange ways. The second command is less known: even with free space, if you run out of inodes no new file can be created. Uncleaned PHP session files or tens of thousands of tiny cache files can do this.

To find what’s taking the space:

sudo du -xh / --max-depth=1 | sort -h

One more trap: deleted files still held open by a process keep using space. If you deleted a big log file and the disk didn’t free up:

sudo lsof +L1

Restarting the service holding the file gives the space back.

6. iostat: can the disk keep up?

It comes with the sysstat package:

iostat -xz 1

If %util stays near 100 and r_await or w_await are in the tens of milliseconds, the disk is the bottleneck. sudo iotop shows which process is using it. The difference between a backup script that runs at 3 a.m. and one that runs at noon usually shows up here.

7. ss: how many connections, from whom?

ss -s
ss -tn state established '( sport = :443 )' | wc -l

The first is a summary, the second counts open connections on port 443. If a number that’s normally 50 has jumped to 2,000, you either ran a very good campaign or someone is scanning you. The web server log tells you which:

sudo awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head

If a single IP is sending thousands of requests, that’s not a visitor, it’s a bot.

8. journalctl: what does the system say?

sudo journalctl -p err -b
sudo journalctl -u nginx --since "1 hour ago"

The first shows errors logged since this boot, the second the last hour of one service. Replace nginx with your own service name, such as php8.3-fpm or mysql.

9. dmesg: did the kernel kill someone?

sudo dmesg -T | grep -iE "out of memory|killed process"

When memory runs out, the kernel’s “OOM killer” kills a process. If your database shuts down “by itself”, look here first. If you see this line, the problem is memory: either the application’s memory settings are too generous or the server is too small.

10. The application itself

If the system side looks clean, it’s the application’s turn. The two suspects I meet most:

  • The database: in MySQL or MariaDB, SHOW FULL PROCESSLIST; shows the queries running right now. If the same query appears dozens of times and has been waiting a while, you’ve found a missing index. For a lasting fix, turn on the slow query log (slow_query_log).
  • PHP-FPM: if its log contains server reached pm.max_children setting, there aren’t enough PHP workers and requests are queueing. How to size that setting is a separate post.

The five-minute routine

To remember in a moment of panic:

  1. uptime: is there load?
  2. top: CPU (us), disk (wa) or neighbour (st)?
  3. free -h and vmstat 1 5: memory and swap
  4. df -h, df -i, iostat -xz 1: disk
  5. ss -s and the access log: traffic
  6. journalctl, dmesg: errors
  7. Database and PHP-FPM logs: the application

One last tip: run these commands once while the server is healthy, too, and note the normal values. Whether “load 3” is good or bad only makes sense if you know what it usually is.

To set a server up right from the start, see the first 30 minutes on a new Linux server.

More from the rulebook

  1. 5 min read

    Tuning PHP-FPM: how to calculate pm.max_children

    Set PHP-FPM's pm.max_children by measuring, not guessing. Measuring process memory, the formula, pm modes, the status page and the slowlog.

  2. 6 min read

    The first 30 minutes on a new Linux server: a security checklist

    What to do in the first half hour on a fresh Ubuntu or Debian server. SSH keys, firewall, fail2ban, automatic updates, swap and a first backup.

Chance

Got a project in mind? Let’s open the box: tell me what you want to build and I’ll prepare a proposal with the scope and a roadmap.

Request a quote

or write directly: email address