Last updated: 23 October 2026. Commands tested on Ubuntu 24.04 (procps 4, sysstat 12). They work the same way on Debian, RHEL, AlmaLinux and Rocky Linux.
A server that suddenly feels slow, a load average that keeps climbing, or a cloud bill that jumps: high CPU usage is one of the most common problems a Linux administrator faces. This guide gives you a repeatable process. First confirm the problem, then find the process (and thread) responsible, work out why it is busy, and fix it without guessing.
Quick checklist
- Compare the load average with the number of CPU cores (
uptime,nproc). - Read the CPU breakdown: user, system, iowait or steal (
top,mpstat). - Find the top processes (
ps,pidstat). - Drill into threads, the service and the logs.
- Fix the cause, or limit the process while you investigate.
- Check for unknown processes (cryptominers are a common cause).
Step 1: Confirm the problem
uptime # load average for the last 1, 5 and 15 minutes
nproc # number of CPU coresThe load average counts processes that are running or waiting to run (and, on Linux, those waiting for disk I/O). Compare it with the number of cores: on a 4-core server a load of 4 means the CPUs are fully used, and a load of 8 means work is queuing. A high load with low CPU usage usually points to a disk or network bottleneck, not the CPU.
Step 2: Read the CPU breakdown
top -b -n 1 | head -15 # one snapshot, sorted by CPU
mpstat -P ALL 1 3 # per-core usage, 3 samples (package: sysstat)
vmstat 1 5 # run queue (r), iowait (wa), steal (st)The %Cpu(s) line in top tells you what kind of load you have:
| Field | Meaning | If it is high |
|---|---|---|
us | User space (applications) | An application is busy: find which one in Step 3 |
sy | Kernel | Many system calls, context switches, network or filesystem work |
wa | Waiting for disk I/O | Not a CPU problem: check the disk with iostat -xz 1 |
st | Steal (virtual machines) | The hypervisor is giving your CPU time to other guests; common on burstable cloud instances that have run out of CPU credits |
si / hi | Soft / hard interrupts | Heavy network traffic or a driver problem |
In mpstat, one core at 100% while the others are idle means a single-threaded process is the bottleneck. Adding cores will not help; the application has to be fixed or scaled out.
Step 3: Find the processes responsible
# Top 10 processes by CPU, with parent PID, user, run time and full command
ps -eo pid,ppid,user,%cpu,%mem,etime,cmd --sort=-%cpu | head -11
# CPU per process over time, more accurate than a single snapshot
pidstat -u 1 5Note that %cpu in ps is an average over the whole life of the process, so a short spike can be hidden. top and pidstat show current usage. A value above 100% means the process is using more than one core.
Step 4: Drill down
PID=1234 # replace with the PID you found
# Which threads inside the process are busy?
top -H -p "$PID"
ps -L -o tid,%cpu,comm -p "$PID" --sort=-%cpu | head
# Which service or container does it belong to?
systemctl status "$PID"
cat /proc/"$PID"/cgroup
# Summary of its system calls for 10 seconds
sudo timeout 10 strace -c -f -p "$PID"
# Recent logs for the service (replace nginx with the unit name)
journalctl -u nginx --since "30 min ago"For deeper analysis, perf top -p PID (package linux-tools-generic on Ubuntu, perf on RHEL) shows which functions are using the CPU. For Java applications, convert the busy thread ID to hexadecimal and look for it in a thread dump (jcmd PID Thread.print). For PHP and other web apps, check the slow log and the web server’s access log for a burst of requests.
Step 5: Common causes and fixes
| Cause | How to spot it | Fix |
|---|---|---|
| Traffic spike or bot crawling | Web server or PHP-FPM workers at the top; access log full of one IP or user agent | Rate-limit, block bad bots, add caching (page cache, CDN) |
| Slow database queries | mysqld or postgres at the top | Enable the slow-query log, add indexes, fix repeated queries |
| Runaway loop or bug | One process at ~100% of a core for a long time | Restart it, then capture threads/stack traces and fix the code |
| Cron or backup jobs | Spikes at the same time every day | Reschedule, run with nice/ionice, spread jobs out |
| Too little capacity | All cores busy with normal, legitimate work | Optimise, scale up or scale out |
| CPU steal / burst credits | st high in top | Move to a non-burstable instance or a larger plan |
| Cryptominer or malware | Unknown process, odd name, runs from /tmp or /dev/shm, unexpected outbound connections | Treat as a security incident (see below) |
Limit a process while you investigate
# Lower the priority of a running process (19 = lowest)
sudo renice -n 10 -p "$PID"
# Run a heavy job at low CPU and disk priority
nice -n 10 ionice -c3 /usr/local/bin/backup.sh
# Cap a systemd service at half of one core (takes effect immediately)
sudo systemctl set-property --runtime myapp.service CPUQuota=50%Remove --runtime to make the CPU quota permanent. Restarting a stuck process with systemctl restart is a valid short-term fix, but always capture evidence (threads, logs) first so you can find the real cause.
When high CPU is a security problem
Unexplained, constant high CPU is a classic sign of a cryptominer, often installed through an unpatched web application or a weak SSH password. Warning signs: a process with a random or kernel-like name that is not a real kernel thread, binaries in /tmp, /var/tmp or /dev/shm, new cron entries, and connections to unknown hosts.
# Where is the binary? A "(deleted)" path or a /tmp location is suspicious
sudo ls -l /proc/"$PID"/exe
# Its network connections
sudo ss -tnp | grep "pid=$PID,"
# Scheduled jobs: per-user crontabs and system cron
sudo ls -la /var/spool/cron/crontabs /etc/cron.d 2>/dev/null
sudo cat /etc/crontabIf you find a miner, do not just kill it: it usually comes back. Isolate the server, preserve evidence, find how the attacker got in, rotate credentials and rebuild from a clean image. Keep the system patched; see our “Black October” fact-check for this month’s critical patches.
Prevent the next spike
- Keep history: enable sysstat collection (
sudo systemctl enable --now sysstat), then review past CPU withsar -u. Without history you can only debug what is happening right now. - Monitor and alert: use a monitoring tool (Prometheus node_exporter, Netdata, Zabbix or your cloud provider’s metrics) and alert on sustained CPU, not single spikes.
- Set limits: give services CPU quotas, and containers CPU limits, so one runaway process cannot take the whole server.
- Patch and harden: most cryptominer infections start with an unpatched service or a weak password. Use our free Linux server hardening checklist.
Frequently asked questions
What is a normal load average?
It depends on the number of cores. A sustained load below the core count is generally fine; consistently above it means work is waiting. Always read it together with the CPU breakdown, because disk waits also raise the load.
Why does top show more than 100% CPU for one process?
By default top shows usage per core, so a process using two full cores shows 200%. Press Shift+I in top to switch to a percentage of total CPU.
Is 100% CPU always bad?
No. Batch jobs, video encoding or compiling are supposed to use all available CPU. It becomes a problem when it slows down important services, lasts longer than expected, or comes from a process you do not recognise.
Need help with a slow or suspicious server? Our Linux server hardening & audit service covers performance and security checks, or contact us.
