A common support ticket reads something like: the site is fast in the morning and crawls in the afternoon, nothing has changed, what is going on? There are only a few usual suspects, and the pattern of when it happens is the best clue. A slowdown at the same time every day points at something scheduled. A slowdown that follows traffic points at limits or caching. A slowdown that comes and goes with no rhythm at all often points outside your server.
The trap is to start fixing before you have looked. Upgrading to a bigger plan feels like action, and sometimes it helps, but if the cause is a backup plugin that reads the whole database at 3 p.m., a larger plan just gives the backup more room to be slow in. This article works through the five usual causes in the order that is cheapest to check, with the evidence each one leaves behind.
Throughout, the goal is the same: match the slow period to a log line, a graph or a timestamp, so that the fix is based on what happened rather than a guess.
Start with the shape of the problem
Before opening any panel, write down four facts. What time does it start, and what time does it end? Is it every day, or only weekdays? Is every page slow or only some (the checkout, the search, the admin area)? And is it slow for everyone, or only for people in one place? Those four answers rule out half the possibilities.
A cheap way to get numbers is to time the same page repeatedly with curl, once an hour for a day, from your own machine:
curl -o /dev/null -s -w "%{time_starttransfer} %{time_total}\n" https://example.com/
The first figure is the time until the first byte arrived, which is the server thinking. The second is the total. If the first figure balloons during the slow period, the server is the problem. If the first figure stays small and the total grows, the page is heavy or a third-party resource is slow to load. The page weight tool helps with the second case.
Scheduled tasks
WordPress uses its own pseudo-scheduler, WP-Cron, which runs when visitors arrive rather than at a fixed time on a clock. Backup plugins, security scans, newsletter sends and search-index rebuilds often run through it. If a heavy job starts at 3 p.m. every day, so does your slowdown.
The visitor-triggered design has two drawbacks. A job can only start when someone loads a page, so on a quiet site it runs late, and on a busy site several visitors can trigger checks at the same moment. Moving heavy jobs to quiet hours, and running them with real server cron instead of visitor-triggered cron, usually helps. The change takes two steps: turn off the built-in trigger in wp-config.php, then call the script from the system scheduler.
define( 'DISABLE_WP_CRON', true );
*/5 * * * * curl -s https://example.com/wp-cron.php?doing_wp_cron > /dev/null 2>&1
The second line goes in the crontab (or the panel's cron page). The cron helper will build the schedule expression if you are not fluent in it. Then look inside the backup or scan plugin and move its start time to the small hours.
Bots
A surprising share of traffic is not human. Search engines, AI crawlers, uptime monitors, vulnerability scanners and scraping tools all request pages, sometimes thousands an hour. A crawler that follows every filter combination in a shop can generate hundreds of thousands of distinct URLs, each of which needs PHP and the database to answer.
Your access log will show which user agents and addresses are responsible. On a server you can count requests per address in a given hour:
grep "05/Oct/2026:15" access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head
If a few addresses account for most of the lines, you have found the load. A firewall rule or a rate limit often removes most of it at no cost to real visitors. For well-behaved crawlers, a robots.txt rule or crawl-delay is a polite first step; for scanners, which ignore it, blocking is the only language they understand. See firewalls and WAFs in this series for how that works.
Resource limits
On shared hosting, your account has caps on CPU, memory and simultaneous processes. Providers describe them differently, but the effect is the same: when you reach the cap, requests queue or fail, often with a 503 or a "resource limit reached" page. The panel often shows a usage graph; if it flattens at a ceiling during the slow period, you have found the limit.
Caching reduces how often PHP has to run and is usually the cheapest fix. A page cache turns a request that needs twenty database queries into a file read. If the graph still sits on the ceiling after caching is working, then a larger plan is a reasonable decision, and you will know why you are buying it.
What differs by hosting type
| Type | Limits look like | Where to look |
|---|---|---|
| Shared | Per-account caps on CPU, memory, processes, I/O | Panel usage graphs, 503 responses |
| VPS | Fixed CPU cores and RAM; swapping when memory runs out | top, free -m, provider graphs |
| Dedicated | Hardware limits only; bottlenecks are usually your own configuration | Same tools, plus disk and database metrics |
| Managed WordPress | Caps on visits, PHP workers and storage | Dashboard analytics, worker count |
The database
Large tables without suitable indexes, a plugin that saves too much to the options table, or a huge number of expired transient records can make queries crawl. A slow query log, or a profiling plugin on a staging copy, will show the culprit quickly. Typical findings: one query that scans a table of a million rows for every page view, or an options table with tens of megabytes of autoloaded data that is read on every request.
On a server you control, switch on the slow query log for a day and look at the top entries:
SET GLOBAL slow_query_log = 1;
SET GLOBAL long_query_time = 1;
Queries over one second are almost always worth a look. Cleaning expired transients and deleting plugin data you no longer use are safe first steps, after a backup.
Something external
Sometimes the slow thing is not your server at all. An embedded video, a tracking script, a font service or a chat widget may be slow to respond, and the page waits. The waterfall in your browser's developer tools (Network tab, reload with the cache disabled) shows it plainly: one long bar from another domain, with everything after it held up.
That slowness often varies by time of day too, because the outside service has its own busy period. If time to first byte from curl stays low while the page feels slow in the browser, suspect this. Load such scripts later, or remove the ones that earn nothing.
Caching in practice
Since caching is the cheapest fix, it is worth knowing what it actually does. A WordPress page is assembled on request: PHP loads the theme and plugins, runs a series of database queries, and builds the HTML. A page cache saves the finished HTML and serves that file to the next visitor, skipping PHP and the database altogether. For a news article read by ten thousand people, the page is built once instead of ten thousand times.
Three things stop it working. Pages that differ per visitor (a basket, an account page) cannot be shared, so good cache rules exclude them. Query strings that vary, such as tracking parameters added by email campaigns, can make every visit look like a new URL unless the cache is told to ignore them. And a cache that is emptied too often, for instance by a plugin that clears everything whenever a comment arrives, protects very little. Check for a response header showing a hit or a miss:
curl -sI https://example.com/ | grep -i -E "cache|age"
Repeat the request twice. If the second answer is not faster, or the header never says hit, the cache is not doing its job.
What to do while you investigate
If the slow period is costing you customers today, there are holding measures that do not need a diagnosis. Pause the backup or scan plugin for a day and see whether the pattern moves. Turn on the host's built-in cache if it has one. Block an obviously abusive address you found in the log. Each of these is reversible, and each gives you information: if pausing the backup makes the slow period disappear, you have your answer without touching anything permanent.
Avoid changing several things at once. If you pause a plugin, add a cache and raise the memory limit in one go and the site speeds up, you will not know which change did it, and the problem will return the next time one of them is undone. Keep a short list of what you changed and when.
Reading the access log for the slow hour
The access log is a diary of every request. For a slowdown, three questions matter: how many requests arrived, who sent them, and what did they ask for? Compare the slow hour with a quiet one. If the slow hour has ten times the requests, you have a traffic problem, whether human or not. If the count is similar but the slow hour has far more requests to one URL such as /wp-admin/admin-ajax.php or a search page, a single feature is the culprit. If the counts are equal and nothing stands out, the load is probably on the server side: a scheduled job, the database, or a neighbour.
grep "05/Oct/2026:15" access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head
That prints the most requested paths for the 15:00 hour. A path appearing thousands of times that you do not recognise deserves a look before anything else.
A worked example
A village theatre's ticket site is quick until mid-afternoon, then pages take eight seconds. Curl shows the first byte arriving after seven seconds at 15:10 and after 0.4 seconds at 11:00. That is the server. The access log shows nothing unusual in volume. The WordPress cron list shows a backup job scheduled for 15:00, and the panel graph shows CPU on the account's ceiling from 15:00 to 15:40.
Moving the backup to 03:00 removes the slowdown. Total cost: five minutes and no change of plan. The same symptom could equally have been a crawler or a database problem, and the process would have been the same.
Checking it yourself
- Record when the slowness starts and ends, for several days.
- Time the first byte with curl at intervals, from outside.
- Open the panel's usage graph for those hours.
- Count requests per address in the access log for the same hour.
- List scheduled tasks and compare their times with the slow window.
- Check the browser waterfall for slow third-party requests.
The method is the same in each case: find the pattern in time, find the matching log or graph, and change one thing at a time. Guessing and upgrading to a larger plan is expensive and often does nothing. The troubleshooting guide and the uptime calculator are useful companions.
Quick answers
Is it my host's fault?
Occasionally, when a neighbour on a crowded server uses too much. The test is if your own graphs and logs show a cause. If they show nothing and the slowness remains, send support your timings.
Will a CDN fix it?
For static files and cached pages, yes. For logged-in or checkout pages that must be built fresh each time, much less.
How much PHP memory should I allow?
Enough for the heaviest legitimate page, which for many WordPress sites is 256 MB. If you need far more, find out what is eating it.
Why does it only happen on weekdays?
Often because a business process runs then: an import, a newsletter, a stock update. Check what your team schedules, as well as what the software does.