• Post author:Bhaskar Soni
  • Post published:
  • Post category:Linux
  • Post comments:0 Comments
  • Reading time:7 mins read

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

  1. Compare the load average with the number of CPU cores (uptime, nproc).
  2. Read the CPU breakdown: user, system, iowait or steal (top, mpstat).
  3. Find the top processes (ps, pidstat).
  4. Drill into threads, the service and the logs.
  5. Fix the cause, or limit the process while you investigate.
  6. 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 cores

The 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:

FieldMeaningIf it is high
usUser space (applications)An application is busy: find which one in Step 3
syKernelMany system calls, context switches, network or filesystem work
waWaiting for disk I/ONot a CPU problem: check the disk with iostat -xz 1
stSteal (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 / hiSoft / hard interruptsHeavy 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 5

Note 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

CauseHow to spot itFix
Traffic spike or bot crawlingWeb server or PHP-FPM workers at the top; access log full of one IP or user agentRate-limit, block bad bots, add caching (page cache, CDN)
Slow database queriesmysqld or postgres at the topEnable the slow-query log, add indexes, fix repeated queries
Runaway loop or bugOne process at ~100% of a core for a long timeRestart it, then capture threads/stack traces and fix the code
Cron or backup jobsSpikes at the same time every dayReschedule, run with nice/ionice, spread jobs out
Too little capacityAll cores busy with normal, legitimate workOptimise, scale up or scale out
CPU steal / burst creditsst high in topMove to a non-burstable instance or a larger plan
Cryptominer or malwareUnknown process, odd name, runs from /tmp or /dev/shm, unexpected outbound connectionsTreat 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/crontab

If 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 with sar -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.

Sources

Post author avatar

Bhaskar Soni

Bhaskar Soni is a Security Engineer and the founder of Youngster Company, based in Ahmedabad, Gujarat. He works hands-on with Linux server hardening, vulnerability assessment and penetration testing (VAPT), ISO 27001 compliance and OSINT investigations. He writes practical, tested guides for IT professionals and Indian businesses, and every article on this site is written or reviewed by him.

Leave a Reply