Skip to main content
linux Beginner Level 8 min read

How to Troubleshoot High CPU Usage on a Linux Server

A step-by-step diagnostic guide to isolate runaway processes, high system load, and thread contention on production Linux servers using top, pidstat, and mpstat.

SC
ServerCare360 Systems Team
Senior Infrastructure Engineer
Published: Sep 18, 2026

When a Linux server runs out of available CPU cycles, websites become slow, SSH sessions lag, scheduled background jobs pile up, and web services may drop incoming visitor connections.

Finding the cause requires a clear diagnostic process. You need to know whether the CPU is busy running user applications, handling system kernel calls, or waiting for slow disk hardware.


Quick Answer

Log in to your server over SSH and run:

top -b -n 1 | head -n 20

Look at the %Cpu(s) line to see if CPU time is spent in user space (us), system kernel space (sy), or disk wait (wa). Then check the top processes listed under the %CPU column. If a single runaway process is consuming all resources, inspect its configuration or restart its service safely.


Symptoms

  • Slow response times on hosted websites and APIs.
  • SSH commands feel delayed or take several seconds to echo back.
  • High load averages reported in monitoring tools like Zabbix or Grafana.
  • Web server 502 Bad Gateway or 504 Gateway Timeout errors.
  • CPU graphs sustained at 90% to 100% across all available cores.

Common Causes

  1. Runaway web application workers: Misbehaving PHP-FPM, Python Gunicorn, or Node.js processes stuck in infinite loops.
  2. Unindexed database queries: MySQL or PostgreSQL running complex full-table scans that consume 100% of single CPU threads.
  3. Crontab script collisions: Resource-heavy maintenance scripts running concurrently instead of sequentially.
  4. Malicious software or cryptominers: Unauthorized processes running hidden inside /tmp or /dev/shm after a CMS plugin compromise.
  5. High system interrupt load: Software interrupt storms or hardware driver issues driving up %sy (system) time.

Before You Start

  • Always record the Process ID (PID) and command line before terminating any process.
  • Avoid using kill -9 immediately on database services. Forcing an abrupt kill on MySQL or PostgreSQL can cause InnoDB table corruption.
  • If you run a high-traffic production system, consider having a team like our Linux server support specialists review your process concurrency before making permanent config changes.

Step 1 — Check Overall CPU Breakdown

The first step is checking how the CPU spends its operational time.

Run the top command:

top

Press 1 on your keyboard while inside top to view the breakdown across individual CPU cores.

Look at the header line starting with %Cpu(s):

%Cpu(s): 85.2 us,  3.1 sy,  0.0 ni, 10.4 id,  0.8 wa,  0.0 hi,  0.5 si,  0.0 st

Here is what each value means:

  • us (User time): CPU time spent running normal user-space processes (Nginx, PHP, MySQL, Node.js). High us points to application workload.
  • sy (System time): CPU time spent inside kernel operations. High sy often indicates excessive system calls or memory management overhead.
  • wa (I/O Wait time): The CPU is idle because it is waiting for disk read/write requests to complete. If wa is high, your bottleneck is disk speed, not CPU capacity.
  • id (Idle time): The percentage of CPU that is currently free.
  • st (Steal time): On virtual machines (VPS, AWS EC2, DigitalOcean), this shows CPU cycles stolen by the hypervisor for other tenants. If st is above 10%, contact your hosting provider.

Press q to exit top.


Step 2 — Identify the Top CPU-Consuming Processes

Now list the top 10 processes consuming the most CPU power right now.

Run this command:

ps -eo pid,ppid,user,%cpu,%mem,cmd --sort=-%cpu | head -n 11

Expected Output

  PID  PPID USER     %CPU %MEM CMD
29481  1204 www-data 98.4  2.1 php-fpm: pool www
29482  1204 www-data 97.8  2.0 php-fpm: pool www
 1102     1 mysql    45.2 18.5 /usr/sbin/mysqld
 8391     1 root      2.1  0.4 /usr/sbin/rsyslogd -n

What This Tells You

  • In the example above, two php-fpm workers (PIDs 29481 and 29482) are consuming nearly 100% of a CPU core each.
  • The user is www-data, confirming these are web requests running application code.
  • If you see an unknown command or a binary running from /tmp, investigate that process immediately for security compromise.

Step 3 — Investigate What the Process Is Doing

Before you kill a process, find out what file or network connection it is using.

Check Open Files for the Process

Replace 29481 with the PID identified in Step 2:

lsof -p 29481

Look for open PHP scripts, log files, or socket connections to databases. This helps locate the exact script causing the spike.

Trace Active System Calls

To see whether a process is stuck in a loop or active processing, attach strace for 5 seconds:

strace -p 29481 -s 128

Press Ctrl + C to detach.

  • If you see rapid, repetitive system calls (like read() or nanosleep() repeating infinitely), the code is trapped in a loop.
  • If you see waiting database queries, move your attention to database query optimization.

Step 4 — Apply the Safe Fix

Scenario A: Runaway PHP-FPM or Web Workers

If web workers are hung, reload the service gracefully instead of killing the server:

# On Ubuntu/Debian:
systemctl reload php8.2-fpm

# On RHEL/AlmaLinux/Rocky:
systemctl reload php-fpm

Reloading allows the master process to terminate hung child workers and spawn fresh workers without dropping active HTTP sessions.

Scenario B: Slow Database Queries Driving High MySQL CPU

Check active running queries inside MySQL:

mysql -e "SHOW FULL PROCESSLIST;" | grep -v "Sleep"

Look for queries that have run for more than 30 seconds with status Sending data or Copying to tmp table.

To terminate a specific stalled query, take its Id from the processlist and run inside the MySQL shell:

KILL 12345;

For persistent database bottlenecks, see our guide on server performance optimization.

Scenario C: Terminate a Rogue or Stuck Process Safely

If a non-critical script is locked and will not exit, send a standard termination signal (SIGTERM):

kill -15 29481

Wait 10 seconds. Check if the PID is gone:

ps -p 29481

Only use kill -9 29481 (SIGKILL) if the process refuses to respond to SIGTERM.


Step 5 — Verify the Fix

Confirm that the CPU usage has dropped back to healthy baseline levels.

Run vmstat to observe CPU trends every 2 seconds:

vmstat 2 5

Healthy Output

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0      0 1845204 128900 2489100    0    0     4    12  320  540  4  2 94  0  0
  • Under the cpu column on the far right:
    • us (user) should be below 30% during normal idle periods.
    • id (idle) should be steady above 70%.
    • r (runnable processes in queue) should not exceed your physical CPU core count.

Common Mistakes

  1. Killing the MySQL daemon instead of the problematic query: Running kill -9 mysqld can corrupt your tables and force a lengthy crash recovery on restart.
  2. Ignoring I/O wait (%wa): Spending hours tuning application code when the real issue is slow storage or an EBS volume running out of IOPS burst credits.
  3. Setting process concurrency too high: Allocating 100 PHP-FPM workers on a 2-core cloud VPS causes severe CPU context switching, making the server slower than running 15 workers.

Prevention Checklist

  • Set pm.max_children in PHP-FPM pool configs to match your available RAM and CPU cores.
  • Enable the MySQL slow query log (slow_query_log = 1, long_query_time = 2) to identify heavy queries before they cause outages.
  • Configure infrastructure monitoring alerts in Prometheus, Grafana, or Zabbix for sustained CPU > 85% over 5 minutes.
  • Use nice and ionice when running heavy background backup scripts so they yield CPU priority to web visitors.

Quick Command Reference

TaskCommand
Interactive CPU monitoringtop (press 1 for per-core view)
Top 10 CPU processesps -eo pid,user,%cpu,%mem,cmd --sort=-%cpu | head -11
View CPU breakdown every 2svmstat 2 5
Check active MySQL queriesmysqladmin processlist
Graceful process terminationkill -15 <PID>
Force process killkill -9 <PID>

Frequently Asked Questions

What is considered a high CPU usage on a Linux server?

Sustained CPU usage above 85% across all cores for more than 10 to 15 minutes is considered high. Short spikes during deployments or scheduled hourly cron jobs are normal, provided the usage drops back down promptly.

How do I know how many CPU cores my server has?

Run nproc or inspect /proc/cpuinfo:

grep -c ^processor /proc/cpuinfo

If your server has 4 cores, a load average up to 4.0 indicates full utilization without queue backlog.

Can high CPU usage cause my server to shut down?

On physical dedicated hardware, sustained 100% CPU can trigger thermal throttling or automated emergency shutdown if server room cooling fails. On virtual cloud instances, the server will not shut down, but Linux may freeze or drop network traffic.

Why is system time (%sy) high while user time (%us) is low?

High %sy means the kernel is working hard. This is usually caused by excessive disk I/O, network packet flooding, memory thrashing using swap space, or high context switching between thousands of competing threads.

How can ServerCare360 help prevent CPU incidents?

Our 24/7 emergency server support and proactive server performance optimization teams audit process pools, tune kernel parameters, configure caching layers (Redis/Varnish), and resolve runaway bottlenecks before your users experience downtime.

Was this technical guide helpful?
Infrastructure Support

Require Proactive Infrastructure Monitoring & Support?

Prevent recurring outages, high load spikes, and backup failures with our 24/7 remote server administration.