Linux Server High CPU: How to Find the Cause in 10 Minutes
By Stackvora Team · 2026-08-06 · 9 min read
"The server is at 100% CPU" is a symptom, not a diagnosis. Linux exposes enough detail to find the real cause in a few minutes — provided you read the right numbers in the right order.
Step 1: Load average versus utilisation
uptime
nproc
Load average counts runnable and uninterruptible processes. A load of 8 on an 8-core box is fully utilised; a load of 8 on a 32-core box is fine. A high load with low CPU usage almost always means disk or network wait, not compute.
Step 2: Split the CPU time
top -1
vmstat 1 5
mpstat -P ALL 1 5
Read the breakdown carefully — each column points somewhere different:
| Column | High value means | Investigate |
|---|---|---|
us user | Application code burning CPU | Profile the process |
sy system | Kernel work: syscalls, context switches | strace, interrupt counts |
wa iowait | Waiting on storage | iostat, disk latency |
si/hi interrupts | NIC or driver pressure | /proc/interrupts, IRQ balance |
st steal | Hypervisor starving the VM | Host contention, noisy neighbour |
Steal time above a few percent on a cloud instance means the problem is not inside your VM at all — resize or move the workload.
Step 3: Identify the process
ps -eo pid,ppid,cmd,%cpu,%mem --sort=-%cpu | head -15
pidstat -u 1 5
top -H -p <pid>
top -H shows per-thread usage — essential for Java, Node and database processes where one thread of many is the culprit. Map the hot thread back to application code:
printf '%x\n' <thread-id> # convert to hex for jstack output
jstack <pid> | grep -A 20 nid=0x<hex>
Step 4: Confirm what it is doing
strace -c -p <pid> -f # syscall summary
perf top -p <pid> # hot functions
cat /proc/<pid>/status | grep -i ctx
A syscall summary answers the key question quickly: heavy read/write means I/O, heavy futex means lock contention, heavy epoll_wait is usually normal idling. Very high voluntary context switches indicate lock or queue contention rather than raw compute.
Step 5: Rule out the usual suspects
- Runaway cron or backup job — check
/var/log/syslogandsystemctl list-timersagainst the spike's start time. - Log flooding — a service writing millions of lines drives both CPU and iowait.
du -sh /var/log/*. - Swap thrashing —
free -handvmstatsi/so columns. Memory pressure presents as CPU pain. - Container limits —
cat /sys/fs/cgroup/cpu.statfor throttling; a throttled container looks slow while the host looks idle. - Crypto mining — an unfamiliar process at 100% with a random name warrants an immediate security review, not a restart.
Step 6: Fix, then verify
Restarting the process clears the symptom and destroys the evidence. Capture first:
ps auxf > /tmp/ps-$(date +%s).txt
top -b -n 1 > /tmp/top-$(date +%s).txt
perf record -p <pid> -- sleep 30
Then apply the appropriate fix: tune the application, add CPU, add an index for the query behind the load, rate-limit the caller, or fix the storage path causing iowait.
Prevention
- Alert on sustained load relative to core count, not raw CPU percentage.
- Record per-process metrics continuously — post-incident,
toptells you nothing about last night. - Set cgroup limits on batch jobs so they cannot starve interactive services.
- Keep a baseline profile of normal behaviour for every production service.
Key takeaways
- Load average and CPU utilisation measure different things — always read both.
- The user/system/iowait/steal split narrows the cause before you name a process.
- Per-thread analysis is essential on JVM and Node workloads.
- Capture evidence before restarting anything.
Database-driven CPU spikes
On application servers, a large share of "high CPU" incidents originate in the database tier. A missing index turns a fast lookup into a sequential scan, the query takes longer, connections pile up, and the application burns CPU serialising and waiting. Before tuning the operating system, check the slowest statements:
-- PostgreSQL
SELECT query, calls, mean_exec_time FROM pg_stat_statements ORDER BY mean_exec_time DESC LIMIT 10;
If one statement dominates, no amount of CPU will fix it — an index or a query rewrite will.
Reproducing safely
When the spike is intermittent, schedule sampling rather than watching a terminal. A small script running top -b -n1, pidstat 1 5 and iostat -x 1 5 into timestamped files every minute costs almost nothing and guarantees you have data the next time it happens. Combine it with process accounting so short-lived processes, which never appear in a manual top, are still recorded.
Ten minutes of structured triage beats an hour of guessing. Paste your mpstat and pidstat output into Stackvora AI for interpretation, and browse the knowledge base for tuning guides on specific workloads.