Your site used to load in under a second. Now it crawls, sometimes it times out completely, and your hosting dashboard is showing a CPU graph that looks like a heart monitor during a stress test. Nine times out of ten this isn't "the internet being slow" — it's a specific process on your server eating more CPU than it should. Here's how to find it and fix it, whether you're on shared cPanel hosting or your own VPS.
Symptom: Slow Pages, Timeouts, or 503 Errors
High CPU usage shows up a few different ways depending on where you're hosted:
- Shared/cPanel hosting: pages load slowly at certain times of day, or you get a
508 Resource Limit Is Reachederror and your account gets temporarily throttled. - VPS:
topor your monitoring panel shows load average well above your core count, SSH sessions feel laggy, and MySQL queries that normally take milliseconds start taking seconds. - Both: visitors report the site "hanging" on load, or you see intermittent 502/503 errors from Nginx or Apache because PHP-FPM workers are all busy and new requests can't get a worker.
Before chasing anything else, confirm it actually is CPU and not RAM or disk I/O — they produce similar symptoms but need different fixes.
Step 1: Find Out What's Actually Using the CPU
On a VPS with SSH access, start with:
top -c
Press Shift+P to sort by CPU usage. Let it sit for 30 seconds — a one-off spike from a cron job is normal, a process that's consistently at the top is your culprit. htop gives you the same view with color and is easier to read if it's installed.
For a longer-running culprit, this one-liner shows the top 10 CPU consumers at a glance:
ps aux --sort=-%cpu | head -n 11
On cPanel shared hosting without shell access, check WHM → Resource Usage (if you're the reseller/admin) or ask your host to pull a CPU usage report for your account — SkyServer support can generate this in a couple of minutes from the backend.
Common Causes, Ranked by How Often We See Them
| Cause | How to confirm it |
|---|---|
| Bot/crawler traffic hammering the same URL | Check access logs for repeated hits from the same IP or user-agent: tail -n 5000 access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head |
| Unoptimized WordPress plugins (especially page builders, backup plugins mid-run, or related-post widgets) | Disable plugins one by one via wp plugin deactivate --all then reactivate in batches, watching CPU each time |
| Runaway or slow MySQL queries | mysqladmin processlist or SHOW FULL PROCESSLIST; — look for queries stuck in "Sending data" for a long time |
| A cron job that's overlapping with itself | Check crontab -l and your process list for duplicate instances of the same script |
Brute-force login attempts (WordPress wp-login.php or SSH) | Grep logs for repeated POST requests to wp-login.php or failed SSH auth attempts in /var/log/auth.log |
| PHP-FPM pool misconfigured with too many workers for available RAM/CPU | Compare pm.max_children in your FPM pool config against actual server resources |
Fix: Match the Cause
It's bot traffic
Block the offending IPs at the firewall level rather than in .htaccess — it's far cheaper on CPU since the request never reaches Apache/PHP:
sudo ufw deny from 203.0.113.44
If it's a known bad crawler (not Googlebot or Bingbot), block by user-agent in Nginx or add a rule in Wordfence/Cloudflare if you're already using either. For repeated offenders, fail2ban with a custom filter for aggressive scraping is worth setting up on a VPS.
It's a plugin or theme
Deactivate the suspect plugin and re-check top. Backup plugins (UpdraftPlus, All-in-One WP Migration) are frequent offenders when a scheduled backup runs during peak traffic — move the schedule to 2–4 AM local time. Page builders and "related posts" plugins that run heavy queries on every page load are the next most common cause; look for a caching option inside the plugin itself, or add object caching (Redis or Memcached) in front of it.
It's MySQL
Kill the stuck query first to stop the bleeding:
KILL <process_id>;
Then find out why it was slow. Missing indexes are the usual reason a query that should take 10ms takes 10 seconds. Run EXPLAIN on the query and check if it's doing a full table scan. On WordPress, the wp_options table with a huge autoload footprint is a classic slow-query source — a plugin gone rogue can bloat this table to hundreds of megabytes.
It's a cron job
Add a lock file check at the start of the script so a slow run doesn't overlap with the next scheduled run:
flock -n /tmp/mycron.lock /path/to/script.sh || exit 1
It's PHP-FPM sizing
If pm.max_children is set higher than your RAM can realistically support, every worker competing for CPU makes everything slower, not faster. A rough starting formula is (Available RAM in MB) / (Average PHP process size in MB). Check average process size with:
ps -ylC php-fpm --sort:rss | awk '{sum+=$8; count++} END {print sum/count/1024 " MB avg"}'
Prevention: Keep It From Coming Back
- Cache aggressively. A page cache (WP Super Cache, W3 Total Cache, or server-level Nginx FastCGI cache) means most visitors never touch PHP or MySQL at all.
- Set up monitoring with alerts. Don't wait for a customer complaint — a simple cron script checking load average, or a monitoring tool like Netdata, can email you before things get bad.
- Rate-limit login pages. Fail2ban for SSH, and a login limiter plugin (or Cloudflare rule) for
wp-login.php, stop brute-force attempts before they cost you CPU cycles. - Review plugins/scripts after every update. A plugin update can silently change default behavior (e.g., start running a heavy scan on every page load).
- Right-size your plan. If you've genuinely outgrown shared hosting — real traffic growth, not just a misconfigured process — moving to a VPS with dedicated CPU cores fixes the "noisy neighbor" problem for good.
If you've gone through this and still can't pin down the cause, open a ticket with your host and share the output of top -c or your resource usage graph — on SkyServer, our support team can trace it from the backend even without you having root access.
Frequently Asked Questions
How do I check CPU usage without SSH access on shared hosting?
Log in to cPanel and look for the "Resource Usage" section (if enabled by your host), which graphs CPU, memory, and I/O over the last 24 hours. If it's not visible, ask your hosting provider to pull the usage report for your account.
What's a normal load average for my server?
As a rule of thumb, load average should stay below the number of CPU cores you have. A 4-core server sitting consistently above 4.0 means requests are queuing up faster than the CPU can process them.
Can too much traffic alone cause high CPU, even with no bugs?
Yes. If your traffic has genuinely grown, the same code that ran fine at 50 visitors/hour can max out CPU at 500 visitors/hour. The fix here is caching and, eventually, more resources rather than debugging code.
Will restarting Apache or PHP-FPM fix high CPU usage?
It can offer temporary relief by clearing stuck processes, but it doesn't fix the underlying cause. If CPU climbs right back up after a restart, you still need to identify and fix the actual source.
Is high CPU usage the same as running out of RAM?
No, though they often show up together. High CPU means processes are competing for processing time; low RAM means the server is swapping to disk, which also slows things down but shows up differently in top (check the swap line, not just the CPU percentage).
