
September 10, 2026
14 min read
By Kokil Thapa | Last reviewed: September 2026
Your monitoring alert fired at 2 a.m. Load average is climbing, pages time out, and SSH feels sluggish. You need to diagnose high CPU and memory usage on a Linux server before a reboot wipes the evidence. On production Ubuntu boxes running Apache, PHP-FPM, and MySQL, the culprit is rarely the kernel itself. It is usually a runaway worker, a stuck queue job, or a query that escaped staging. This guide walks through the exact commands and decision paths I use on real client servers.
uptime, top or htop, and free -h first, then identify the top PIDs with ps or systemd-cgtop, map each process to its service unit, inspect logs, and fix or restart the specific offender—not the whole machine.How do you diagnose high CPU and memory usage on a Linux server?
Start with a 60-second triage loop. You want three numbers: load average, available memory, and the top five processes by CPU or RSS. Do not reboot yet. A reboot destroys the process list and often hides the root cause.
Connect over SSH and run these commands in order:
uptime— shows load averages for 1, 5, and 15 minutes.free -h— shows total, used, and available memory plus swap.top -b -n 1 | head -20— one snapshot of the heaviest processes.df -h— confirms disk is not full; a full disk causes I/O wait that looks like CPU load.
Compare load average to your CPU core count. On a 4-core VPS, sustained load above 4.0 means every core is busy. If load is high but CPU idle percentage in top is also high, suspect I/O wait—not compute saturation. That pattern often points to slow disk, a missing index, or a backup job hammering the filesystem.
Write down the timestamp, load values, and top PIDs before you change anything. If the incident is on a Laravel app, note whether queue workers, schedulers, or web requests correlate with the spike. Persistent monitoring from tools like Netdata with alert thresholds makes this triage faster because you already know which graph moved first.
Reading load average versus CPU percentage
Load average counts runnable and uninterruptible tasks. It does not distinguish CPU-bound from disk-bound work. Press 1 in interactive top to see per-CPU usage. If wa (I/O wait) dominates, check MySQL slow logs and backup cron jobs before blaming PHP.
Understanding memory: used versus available
On modern Linux kernels, free -h shows an available column that includes reclaimable page cache. Do not panic when used looks high. Panic when available approaches zero and swap usage climbs. The kernel's proc filesystem documentation explains how /proc/meminfo fields relate to OOM behaviour.
Which Linux commands show the highest CPU and memory consumers?
Different tools answer different questions. Use the right one instead of guessing from a single top screen.
| Command | Best for | Limitation |
|---|---|---|
top / htop | Live CPU and memory ranking | Hard to correlate with systemd units |
ps aux --sort=-%mem | head | Snapshot of top memory PIDs | Static; misses short spikes |
systemd-cgtop | Resource use per cgroup/service | Requires systemd; less detail per thread |
smem -rs pss | Accurate shared memory attribution | Not installed by default on minimal images |
pidstat -r 1 5 | Memory trends per PID over time | Part of sysstat package |
For a quick memory snapshot sorted by resident set size:
ps aux --sort=-%mem | head -15
ps aux --sort=-%cpu | head -15 To see which systemd unit owns a process, use the PID you captured:
systemctl status <PID>
cat /proc/<PID>/cgroup On servers I maintain with Apache and PHP-FPM 8.3 or 8.4, systemd-cgtop often shows php8.3-fpm.service or mysql.service at the top within seconds. That immediately narrows the search. For deeper service control patterns, see how systemd manages services on Linux.
Installing and using htop
htop adds tree view, colour cues, and F6 sort options. Install on Ubuntu with sudo apt install htop. Press F5 for process tree—useful when one parent spawns dozens of PHP workers. Press F6 and sort by PERCENT_MEM or PERCENT_CPU.
Capturing evidence before you kill a process
Before sending SIGKILL, dump state:
PID=12345
ps -fp $PID
cat /proc/$PID/cmdline | tr '\0' ' '; echo
ls -l /proc/$PID/fd 2>/dev/null | wc -l
sudo cat /proc/$PID/stack 2>/dev/null The open file descriptor count matters for PHP apps with leaked connections. A worker holding hundreds of sockets often points to a database or Redis handle that never closed. Related reading: PHP memory limits and common leak patterns.
How do you trace high CPU usage to PHP-FPM, MySQL, or queue workers?
Web stacks follow predictable patterns. Map the process name to the layer, then open that layer's logs.
PHP-FPM workers stuck at 100% CPU
PHP-FPM pool processes appear as php-fpm: pool www or php8.3-fpm: pool www. When every worker is busy, new requests queue and the site hangs. Check pool status if enabled in /etc/php/8.3/fpm/pool.d/www.conf:
pm.status_path = /fpm-status
ping.path = /fpm-ping Query status with curl from localhost (protect this path in production):
curl -s http://127.0.0.1/fpm-status?full Look for max children reached in /var/log/php8.3-fpm.log. That means your pool is undersized or requests are too slow. Tuning guidance lives in PHP-FPM tuning for high-traffic websites and PHP-FPM configuration for high-traffic sites.
To sample what a hot PHP worker is doing, use strace briefly:
sudo strace -p <PID> -c -f -t 2>&1 | head -30 Heavy read or poll syscalls on a database socket mean a slow query, not bad PHP code. Heavy write to a log file may mean debug logging left on in production.
MySQL consuming RAM or CPU
mysqld often tops memory on LAMP stacks. MySQL 9.7 and the 8.4 LTS line both cache aggressively. Check current connections and running queries:
mysql -e "SHOW FULL PROCESSLIST;"
mysql -e "SHOW GLOBAL STATUS LIKE 'Threads_running';" Enable the slow query log temporarily if you suspect bad SQL. Long-running SELECT statements with Using filesort or full table scans burn CPU and block InnoDB threads. Fix queries before buying a bigger VPS. Start with optimizing MySQL queries for high-traffic applications.
Laravel queue workers and cron overlap
Background jobs appear as php artisan queue:work or supervisor-managed processes. A stuck job retrying every second can saturate CPU across multiple workers. I've seen this on production Laravel applications when a third-party API times out but the job lacks backoff.
Inspect the queue and failed jobs table, then read scaling Laravel background jobs. Check cron with grep CRON /var/log/syslog—overlapping schedulers are a common mistake when both system cron and Laravel's scheduler fire the same export.
What causes sudden memory spikes on a Ubuntu web server?
Memory spikes usually fall into five categories. Match symptoms to the category before you change pool sizes blindly.
- PHP-FPM pool too large:
pm.max_childrenmultiplied by per-worker RSS exceeds RAM. - MySQL buffer overcommit:
innodb_buffer_pool_sizeplus connection buffers eats most of the box. - Cache stampede: expired keys trigger simultaneous regeneration across workers.
- Log or backup jobs:
gzip,tar, ormysqldumpspiking memory during nightly cron. - Memory leak: worker RSS grows over hours until the OOM killer strikes.
Estimate safe PHP-FPM children with this rough formula:
available_ram_mb / average_php_worker_mb = safe max_children upper bound Measure average worker RSS while traffic is normal:
ps -o rss= -C php-fpm8.3 | awk '{sum+=$1; n++} END {print sum/n/1024 " MB avg"}' On a 4 GB VPS running MySQL and Redis, leaving headroom for the OS means PHP might get 1.2–1.5 GB—not 3 GB. A site like Adventure Third Pole Trek with Livewire and booking logic needs realistic pool math, not default www.conf values copied from a tutorial.
Detecting the OOM killer
When the kernel runs out of memory, it kills a process—often MySQL or a fat PHP worker. Check:
dmesg -T | grep -i "out of memory"
journalctl -k | grep -i oom If OOM events appear weekly, your capacity plan is wrong or a leak exists. Adding swap on a small VPS buys time but does not fix bad pool sizing. Swap thrash feels like a CPU problem because the kernel spends cycles paging.
Redis and Memcached memory caps
Redis 8.10 defaults can grow until maxmemory is hit. Check:
redis-cli INFO memory | grep used_memory_human
redis-cli CONFIG GET maxmemory Set an explicit maxmemory and eviction policy so cache does not consume the entire box. For cache architecture decisions, read caching strategies for high-traffic sites.
How do you fix runaway processes without rebooting the server?
Rebooting is a last resort. It clears opcache, drops established DB connections, and interrupts in-flight payments. Fix the specific offender instead.
Graceful service restart order
On a typical PHP stack, restart in this order:
- Stop the bleeding: rate-limit traffic at the firewall or CDN if needed.
- Restart PHP-FPM:
sudo systemctl reload php8.3-fpm(graceful) orrestartif workers are stuck. - Identify and kill long MySQL queries:
KILL <id>;after confirming withSHOW PROCESSLIST. - Restart queue workers via Supervisor:
sudo supervisorctl restart all. - Only then consider MySQL restart during a maintenance window.
The systemctl manual documents the difference between reload and restart. PHP-FPM reload spawns new workers and retires old ones—prefer it during business hours on Nepali e-commerce sites where downtime costs real revenue.
Setting temporary resource limits
Use systemd drop-in overrides to cap a runaway service while you debug:
sudo systemctl edit php8.3-fpm Add:
[Service]
MemoryMax=1500M
CPUQuota=200% Then sudo systemctl daemon-reload && sudo systemctl restart php8.3-fpm. This prevents one pool from taking the entire machine. Remove the limit after you fix the underlying query or code path.
When killing a single PID is correct
If one PHP worker is pegged at 100% CPU for 10+ minutes while siblings are idle, kill that PID:
sudo kill -15 <PID> PHP-FPM master will spawn a replacement. Use SIGTERM first. Reserve SIGKILL for workers that ignore graceful shutdown. Document the PID and request URL if you can trace it from access logs.
After stabilizing, schedule proper fixes: query indexes, queue backoff, PHP-FPM pool tuning, or a scheduled upgrade window. For ongoing incidents on busy storefronts, see hosting a high-traffic Nepali e-commerce site.
How do you prevent repeat CPU and memory incidents?
Diagnosis without prevention means you will be awake at 2 a.m. again next month. Build three layers: monitoring, alerting, and capacity headroom.
Monitoring and alert thresholds
Set alerts on load average, available memory percentage, swap usage, and PHP-FPM max children reached count. A load alert at 1.5× core count gives you time to act before customers notice. Combine Netdata or Nagios with the practices in Ubuntu server monitoring guide and Nagios monitoring for servers.
Log rotation and structured exports
Runaway disk from verbose logging causes I/O wait spikes. Ensure logrotate is configured for PHP, Apache, and MySQL logs. When exporting JSON log snippets for analysis, a JSON formatter helps validate structure before you paste into tickets or CI pipelines.
Security and abuse traffic
CPU spikes from brute-force login attempts or scraper floods look like application bugs. Check Apache access logs for repeated 404s or POST floods to wp-login.php. Pair resource monitoring with website and server security practices in Nepal and baseline hardening from Ubuntu web server hardening.
Post-incident checklist
After every spike, document:
- Start and end time, peak load, and peak memory.
- Top three PIDs and their systemd units.
- Whether OOM killer fired.
- Code deploy, cron change, or traffic event that correlated.
- Permanent fix applied and who owns follow-up.
For teams without in-house ops capacity, support and maintenance or speed optimization engagements often start with exactly this incident log. A proper Ubuntu server setup for PHP apps done right the first time prevents many of these fires.
Key Takeaways
- Run
uptime,free -h, andtopbefore killing processes—capture PIDs and timestamps first. - Map each hot PID to a systemd unit; PHP-FPM, MySQL, Redis, and queue workers have different log paths.
- High load with high I/O wait points to disk or database problems, not always CPU-bound PHP code.
- Size PHP-FPM
max_childrenfrom measured worker RSS, not guesswork—leave RAM for MySQL and the OS. - Prefer
systemctl reload php8.3-fpmand targetedKILLqueries over a full reboot. - Install monitoring with alerts on load, available memory, and FPM pool exhaustion to catch the next spike early.
People Also Ask
What is a dangerous load average on a Linux server?
Sustained load above your CPU core count is a warning sign on a web server. Brief spikes during backups may be acceptable. If load stays high for 5+ minutes while response times degrade, treat it as an incident and start triage immediately.
How much swap should a web server use?
Ideally none during normal operation. Small amounts of swap use during off-peak jobs can be fine. Heavy, continuous swap in and out means RAM is undersized or a service is overcommitted—fix sizing before adding more swap space.
Can a single bad MySQL query crash the server?
A single unindexed query on a large table can peg CPU and block other connections. It rarely crashes the kernel, but it can exhaust the connection pool and PHP-FPM workers waiting on DB responses. Kill the query ID after confirming it in SHOW PROCESSLIST.
Should I install more RAM or optimize the application first?
Optimize first if memory grew suddenly after a deploy or config change. Add RAM if baseline usage legitimately increased with traffic and tuning is already sane. Buying a bigger VPS without fixing a leak only delays the next OOM event.
Next steps after you diagnose the spike
Knowing how to diagnose high CPU and memory usage on a Linux server turns a panic reboot into a 15-minute fix. Capture evidence, identify the service layer, read the right logs, and apply a targeted restart or config change. Then close the loop with monitoring and pool sizing so the same failure mode cannot silently return.
If your production stack runs Laravel, WooCommerce, or custom PHP on Ubuntu and you want someone who handles both the app and the box, review the portfolio or reach out via contact us for a structured health check. For background on baseline server layout, start with Ubuntu server setup guide and keep about me handy if you want to know who will actually SSH in at 2 a.m.
Frequently Asked Questions
0 Comments
Leave a comment
Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

