When a server feels slow, the first question is which resource is saturated and which process is responsible. Four classic terminal tools answer it: top and htop for CPU and memory, iotop for disk I/O and iftop for network bandwidth. In this tutorial you will install them on Ubuntu 24.04, learn to read the numbers that matter and use them to track down a real bottleneck.
Prerequisites
To follow this guide you need:
- A server running Ubuntu 24.04 LTS, for example a CubePath VPS. The tools work the same on Debian 12; on Rocky Linux 9, install
htopandiftopfrom EPEL. - A non-root user with
sudoprivileges.iotopandiftopneed root to read kernel counters and capture packets.
Step 1 - Installing the tools
top is part of the procps package and is always installed. Install the other three:
sudo apt update
sudo apt install htop iotop iftop
Verify that they are available:
htop --version
iftop -h 2>&1 | head -n 1
command -v iotop
htop 3.3.0
iftop: display bandwidth usage on an interface by host
/usr/sbin/iotop
Step 2 - Reading the system summary in top
Start top:
top
The first five lines are the most useful part of the screen:
top - 10:42:17 up 12 days, 3:05, 1 user, load average: 2.14, 1.08, 0.61
Tasks: 142 total, 2 running, 140 sleeping, 0 stopped, 0 zombie
%Cpu(s): 46.3 us, 4.1 sy, 0.0 ni, 37.2 id, 11.8 wa, 0.0 hi, 0.3 si, 0.3 st
MiB Mem : 3915.2 total, 214.6 free, 2140.8 used, 1829.4 buff/cache
MiB Swap: 2048.0 total, 1998.0 free, 50.0 used. 1774.4 avail Mem
How to read them:
- load average: the average number of processes running or waiting for CPU or disk over 1, 5 and 15 minutes. Compare it with the number of vCPUs (
nproc). On a 2 vCPU server, a sustained load above 2 means work is queuing. Here the 1-minute value is rising above the 15-minute one, so the load is increasing. - us / sy: CPU time spent in user programs and in the kernel. High
uspoints to your application; highsyoften to heavy I/O or many system calls. - wa (I/O wait): the CPU is idle waiting for the disk. A consistently high value, like the 11.8 above, means the disk is the bottleneck, not the CPU. Use
iotop(Step 5) to find out who is reading or writing. - st (steal): time the hypervisor gave your vCPU to another virtual machine. On a VPS, a steal value that stays above a few percent means you are short of CPU capacity.
- avail Mem: memory available for new work without swapping. Ignore
free: Linux uses spare RAM as disk cache (buff/cache) and gives it back when needed. Worry whenavail Memis low and swapusedkeeps growing.
Below the summary is the process list. The columns to watch are %CPU, %MEM, RES (physical memory used by the process) and S (state: R running, S sleeping, D uninterruptible sleep, usually waiting for disk, Z zombie).
Step 3 - Using top interactively and in scripts
While top is running, these keys change what you see:
| Key | Action |
|---|---|
P | Sort by CPU usage (default) |
M | Sort by memory usage |
1 | Show each CPU core separately |
c | Show the full command line instead of the program name |
u | Show only processes of one user |
k | Send a signal to a PID (default SIGTERM) |
q | Quit |
You can also set the sort order and filters from the command line. To watch only the processes of the www-data user sorted by memory:
top -u www-data -o %MEM
To follow specific PIDs, for example all PostgreSQL processes:
top -p "$(pgrep -d, postgres)"
Batch mode (-b) prints plain text instead of a live screen, which is useful to capture a snapshot when an alert fires or to attach to a ticket. This prints one iteration and keeps the summary plus the 10 heaviest processes:
top -b -n 1 -o %CPU | head -n 17
Step 4 - Working faster with htop
htop shows the same data with per-core CPU bars, color-coded memory usage, mouse support and a process tree. Start it:
htop
The CPU bars are split by color: green for user processes, red for the kernel, and, once enabled in the setup screen, gray for I/O wait and other colors for steal. The memory bar distinguishes used memory (green) from buffers and cache.
The function keys are listed at the bottom of the screen:
| Key | Action |
|---|---|
F3 or / | Search for a process by name |
F4 or \ | Filter the list to matching processes only |
F5 or t | Toggle tree view to see parent and child processes |
F6 or < > | Choose the sort column |
Space | Tag a process (tag several to act on all of them) |
F9 or k | Send a signal to the selected or tagged processes |
F2 | Setup: add meters, columns and color options |
H | Hide or show user threads |
Tree view is particularly useful on servers: it shows, for example, that 40 php-fpm processes all belong to one pool master, or which parent keeps spawning short-lived children.
htop also accepts start-up options. To show only one user's processes in tree view:
htop -u www-data -t
Settings you change with F2 are saved in ~/.config/htop/htoprc for your user.
Step 5 - Finding disk I/O hogs with iotop
top tells you the disk is the bottleneck (high wa), but not who is using it. iotop shows read and write bandwidth per process.
Since Linux 5.14, the kernel does not collect per-task delay accounting by default, so the IO> and SWAPIN percentages in iotop stay empty. Enable it for the current boot:
sudo sysctl kernel.task_delayacct=1
To keep it after a reboot, add it to a sysctl drop-in file:
echo 'kernel.task_delayacct = 1' | sudo tee /etc/sysctl.d/60-iotop.conf
Now run iotop, showing only processes that are actually doing I/O (-o):
sudo iotop -o
Total DISK READ: 12.34 M/s | Total DISK WRITE: 48.71 M/s
Current DISK READ: 12.30 M/s | Current DISK WRITE: 52.90 M/s
TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
2231 be/4 mysql 10.96 M/s 41.02 M/s 0.00 % 78.41 % mysqld
5120 be/4 root 1.34 M/s 7.61 M/s 0.00 % 12.03 % rsync -a /var/www/ /backup/
The IO> column is the share of time the thread spent waiting for I/O. In this example MySQL causes most of the load, and a backup rsync competes with it.
Other useful options:
sudo iotop -o -Pshows processes instead of individual threads.sudo iotop -o -ashows accumulated I/O sinceiotopstarted instead of current bandwidth, which reveals processes that write in short bursts.sudo iotop -o -b -n 5 -d 2prints five samples, two seconds apart, as plain text for logs or tickets.
If a backup job is the problem, you can lower its I/O priority instead of stopping it:
sudo ionice -c 3 -p 5120
Class 3 (idle) means the process only gets disk time when nobody else needs it.
Step 6 - Measuring network bandwidth with iftop
iftop shows which connections are using bandwidth on an interface, similar to top for network traffic. First find your public interface name:
ip -br addr
lo UNKNOWN 127.0.0.1/8 ::1/128
eth0 UP 203.0.113.10/24 2001:db8::10/64
Run iftop on that interface. -n disables DNS lookups (which would add traffic and slow the display), -P shows ports and -B shows bytes instead of bits:
sudo iftop -i eth0 -n -P -B
203.0.113.10:443 => 198.51.100.24:51522 1.21MB 1.05MB 987KB
<= 22.4KB 19.8KB 18.1KB
203.0.113.10:22 => 192.0.2.55:60114 3.10KB 2.85KB 2.64KB
<= 416B 390B 402B
----------------------------------------------------------------------
TX: cum: 48.2MB peak: 1.34MB rates: 1.21MB 1.07MB 991KB
RX: 1.10MB 31.0KB 23.2KB 20.6KB 19.1KB
TOTAL: 49.3MB 1.37MB 1.23MB 1.09MB 1.01MB
Each pair of lines is one connection: => is traffic sent, <= is traffic received. The three columns are average rates over the last 2, 10 and 40 seconds. Here most outgoing traffic is HTTPS to a single client, typical of a large download.
Keys while iftop runs: p toggles ports, n toggles DNS resolution, t cycles the line display, 1/2/3 sort by the 2, 10 or 40 second column, and q quits.
To focus on specific traffic, pass a packet filter with -f. For example, only web traffic:
sudo iftop -i eth0 -n -P -f 'port 80 or port 443'
Step 7 - Putting it together: a troubleshooting workflow
When an alert fires or users report slowness, work through the resources in order:
- Run
topand look at the load average againstnproc, then atus,waandst. - If
usorsyis high, sort by CPU (P) intoporhtopand look at the heaviest processes. Use tree view inhtopto see which service they belong to. - If
wais high or processes sit in stateD, runsudo iotop -o -Pto find the process reading or writing. - If
avail Memis low and swap usage grows, sort by memory (M). Checksudo journalctl -k | grep -i 'out of memory'to see if the kernel has already killed processes. - If CPU, disk and memory look normal but the service is slow or the link is saturated, run
sudo iftop -i eth0 -n -Pto see who is using the bandwidth.
These tools only show the present moment. For history and alerting, you need a metrics system that records the same data over time.
Troubleshooting
iotopshowsCONFIG_TASK_DELAY_ACCT not enabled in kernel, cannot determine SWAPIN and IO %: delay accounting is off. Enable it withsudo sysctl kernel.task_delayacct=1as shown in Step 5.iftop: pcap_open_live(eth0): eth0: No such device exists: the interface has a different name, such asens3orenp1s0. List interfaces withip -br addrand pass the right one with-i.iftopshows no traffic orPermission denied: it needs root to capture packets. Run it withsudo.htopcolors look wrong or the screen is garbled over SSH: your terminal type is not recognized. TryTERM=xterm-256color htop.
Conclusion
You can now use top and htop to see CPU and memory pressure, iotop to find the processes behind disk I/O wait and iftop to see which connections use your bandwidth, and you know which numbers in each tool point to a real bottleneck. As next steps, learn to read system logs with journalctl to see why a process misbehaved, and set up a metrics and alerting stack so you are notified before a resource runs out.
