Website Slow or Server Under High Load: How to Find the Cause
To find out why a website is slow, measure the time to first byte (TTFB) first. If TTFB is high (well over one second), the server is slow to generate the page, so check resource limits, server load, slow database queries, PHP workers and bot traffic. If TTFB is fast but the page still loads slowly, the problem is front-end weight: large images, too many scripts or no page caching. This guide covers both cases on Cloudesta shared cPanel hosting and on a Cloud VPS or dedicated server running Ubuntu 24.04 (the commands also work on 22.04).
Prerequisites
- The URL of the slow page, for example
https://example.com/. - Shared hosting: your cPanel login.
- VPS or dedicated server: SSH access as root or a sudo user, and your MySQL/MariaDB root credentials.
- For WordPress database checks: phpMyAdmin (cPanel) or WP-CLI (VPS).
1. How do I measure how slow my website really is?
Run the page through PageSpeed Insights or GTmetrix and note the TTFB, the total page size and the number of requests. Then measure TTFB yourself from a terminal so you can repeat the test after each change:
curl -o /dev/null -s -w 'TTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n' https://example.com/
Run it three or four times. The first request is often slower because caches are cold. Write down the figures so you have a baseline.
2. Is the problem the server or the page itself?
- TTFB under about 0.8 s, but the page takes several seconds to load: this is front-end weight. Look at the GTmetrix waterfall for large images, many third-party scripts and render-blocking CSS/JS. Compress images, convert them to WebP, lazy-load them and remove unused plugins or embeds.
- TTFB above 1–2 s: the server is slow to build the page. Continue with section 3 (shared hosting) or section 4 onwards (VPS).
- TTFB is fast for static files but slow for PHP pages: the cause is PHP, the database or missing page caching.
3. How do I find the cause on cPanel shared hosting?
Check CloudLinux resource limits
Go to cPanel » Metrics » Resource Usage. If the account has reached its CPU, physical memory (PMEM), entry processes (EP) or IO limits, CloudLinux slows it down, and the faults appear here with timestamps. Compare those times with when visitors reported slowness. EP faults usually mean too many simultaneous uncached PHP requests, which are often caused by bots.
Look for bot traffic in AWStats
Open cPanel » Metrics » Awstats and check the "Robots/Spiders visitors" and "Hosts" tables. A single crawler or IP address making tens of thousands of hits is a common cause of resource faults.
Enable LiteSpeed Cache and optimise images
Cloudesta shared servers run LiteSpeed, so on WordPress install the free LiteSpeed Cache plugin and enable page caching. Cached pages are served without running PHP, which cuts both TTFB and CPU use. In the same plugin, use Image Optimization to create WebP versions of your images. Also open cPanel » Software » Select PHP Version and make sure the opcache extension is ticked.
4. How do I check if my VPS is under high load?
uptime
nproc
uptime shows the load average over 1, 5 and 15 minutes. Compare it with the CPU count from nproc. A load of 3.5 on a 4-core server is busy but fine. A sustained load of 12 on 4 cores means work is queuing. Next, see which processes are responsible:
sudo apt update && sudo apt install -y htop
htop
Sort by CPU (F6) or memory. In plain top, press P or M to sort, and 1 for per-core usage. A high wa (iowait) value points to slow disk access, usually caused by the database. Heavy swap use means you are short of RAM. Many php-fpm or mysqld processes at the top tell you which of the next two sections to read first.
5. How do I find slow MySQL queries?
Enable the slow query log at runtime. These settings apply until the next restart:
sudo mysql -e "SET GLOBAL slow_query_log_file='/var/log/mysql/mysql-slow.log'; SET GLOBAL long_query_time=1; SET GLOBAL slow_query_log=1;"
Let the site run for an hour, then summarise the log by total time spent:
sudo mysqldumpslow -s t /var/log/mysql/mysql-slow.log | head -30
To make the setting permanent, add slow_query_log = 1, long_query_time = 1 and the log file path under [mysqld]. The file is /etc/mysql/mysql.conf.d/mysqld.cnf for MySQL or /etc/mysql/mariadb.conf.d/50-server.cnf for MariaDB. Then get tuning suggestions for buffer sizes:
sudo apt install -y mysqltuner
sudo mysqltuner
6. Is PHP-FPM running out of workers?
The PHP version is 8.3 on Ubuntu 24.04 and 8.1 on 22.04. Adjust the paths below to match. First check the log:
sudo grep -i "max_children" /var/log/php8.3-fpm.log
If you see "server reached pm.max_children", requests are waiting for a free worker. For live figures, uncomment pm.status_path = /status in /etc/php/8.3/fpm/pool.d/www.conf and add this block inside your Nginx server { } block:
location = /status {
allow 127.0.0.1;
deny all;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $fastcgi_script_name;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
sudo nginx -t && sudo systemctl reload nginx php8.3-fpm
curl -H "Host: example.com" http://127.0.0.1/status
Check the "active processes", "listen queue" and "max children reached" values. Raise pm.max_children only if you have free RAM. Each worker typically uses 40–100 MB. If RAM is tight, fix caching and bots first.
7. How do I spot bots in the access log?
Use /var/log/nginx/access.log for Nginx or /var/log/apache2/access.log for Apache. The following one-liners show the top IP addresses, user agents and URLs:
sudo awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20
sudo awk -F'"' '{print $6}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20
sudo awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20
Repeated hits on /wp-login.php or /xmlrpc.php point to brute-force attempts. Thousands of requests from SEO crawlers point to aggressive indexing. To slow down well-behaved crawlers, add rules like this to robots.txt:
User-agent: AhrefsBot
Crawl-delay: 10
User-agent: MJ12bot
Disallow: /
Abusive bots ignore robots.txt, so block them with a firewall rule or use fail2ban:
sudo ufw deny from 203.0.113.10
sudo apt install -y fail2ban
printf '[nginx-botsearch]\nenabled = true\n' | sudo tee /etc/fail2ban/jail.d/nginx-botsearch.local
sudo systemctl restart fail2ban
8. How do I enable OPcache and an object cache?
OPcache is usually enabled by default on Ubuntu. Tune it in /etc/php/8.3/fpm/conf.d/10-opcache.ini:
opcache.enable=1
opcache.memory_consumption=256
opcache.max_accelerated_files=20000
To add Redis as an object cache, which keeps repeated database lookups in memory, run:
sudo apt install -y redis-server php8.3-redis
sudo systemctl restart php8.3-fpm
Then, in WordPress, install the "Redis Object Cache" plugin and click Enable Object Cache.
9. Is database bloat slowing down WordPress?
WordPress loads every autoloaded row in wp_options on every request. Run the following queries in phpMyAdmin or mysql, adjusting the table prefix if yours is not wp_:
SELECT ROUND(SUM(LENGTH(option_value))/1024) AS autoload_kb
FROM wp_options WHERE autoload IN ('yes','on','auto-on','auto');
SELECT option_name, LENGTH(option_value) AS bytes
FROM wp_options WHERE autoload IN ('yes','on','auto-on','auto')
ORDER BY bytes DESC LIMIT 20;
More than about 1 MB of autoloaded data is a problem. Large entries usually belong to plugins you have removed. To clear expired transients, run this from the site directory:
wp transient delete --expired
wp_options. On shared hosting, you can also restore from JetBackup if something goes wrong.10. When is it simply too much traffic for my plan?
You may have caching enabled, bots blocked and slow queries fixed, yet CPU or entry processes are still at the limit during normal visitor traffic. In that case the site has outgrown its plan. Shared hosting accounts can move to a larger shared hosting package. Busy or custom applications are better served by a Cloud VPS with dedicated resources. Plan upgrades are carried out by Cloudesta, so open a support ticket to request one.
Verify it works
- Re-run the
curlTTFB test and compare the result with your baseline. - Re-test in PageSpeed Insights or GTmetrix.
- On a VPS, check that the load average in
uptimestays belownprocat peak times. - On shared hosting, check that no new faults appear in Resource Usage.
Common problems
- Site returns "508 Resource Limit Reached" on shared hosting: entry processes are exhausted. Enable LiteSpeed Cache and block the bots you found in AWStats.
- Load is high but CPU is mostly idle: the server is waiting on disk (iowait) or swapping. Check slow queries and memory use.
- Pages return 502 or 504 errors under load: PHP-FPM has reached
pm.max_children. Add caching, or raise the limit if RAM allows. - Redis is installed but nothing changed: PHP-FPM was not restarted, or the WordPress object cache plugin was never enabled.
- The site is slow only for logged-in users: page cache is bypassed for logged-in sessions. Add an object cache and reduce the number of admin plugins.
Frequently asked questions
What is a good TTFB?
Under 0.8 seconds is generally considered good. A cached page on LiteSpeed or Nginx is often under 0.2 seconds.
What load average is too high?
A load that stays above your CPU core count for 5–15 minutes means processes are queuing. Short spikes are normal.
Will blocking bots hurt my SEO?
Not if you leave Googlebot and Bingbot alone. Blocking aggressive third-party crawlers and attack traffic does not affect search engine rankings.
Need help? If you cannot find the cause, or you need a plan upgrade, open a support ticket with your domain, the times the slowness occurred and the output of the checks above.