Stackvora.tech

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:

ColumnHigh value meansInvestigate
us userApplication code burning CPUProfile the process
sy systemKernel work: syscalls, context switchesstrace, interrupt counts
wa iowaitWaiting on storageiostat, disk latency
si/hi interruptsNIC or driver pressure/proc/interrupts, IRQ balance
st stealHypervisor starving the VMHost 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/syslog and systemctl list-timers against 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 -h and vmstat si/so columns. Memory pressure presents as CPU pain.
  • Container limits — cat /sys/fs/cgroup/cpu.stat for 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, top tells 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.

More blog posts · Knowledge base