When a WordPress site becomes slow, “WordPress is slow” is a description of the symptom rather than the cause. The delay may occur before WordPress starts, inside PHP, during a database query, while a plugin waits for an external service, or because a request that should have been cached is unexpectedly reaching the dynamic application.
The fastest route to a useful diagnosis is to identify which requests are slow, which layer is doing the work, and what changed.
Do not begin by tuning everything. First find the layer that is actually consuming the time or capacity.
Start with the request path
The hosting architecture guide explains these boundaries in more detail.
First question: is everything slow?
Test more than the homepage. Compare a static asset, a cacheable public page, an uncached page and wp-admin where appropriate.
If static files are fast but uncached WordPress pages are slow, the network and Nginx may be functioning normally while the delay sits deeper in the dynamic path. If only wp-admin is slow, full-page caching is largely irrelevant because administrative requests are intentionally dynamic.
If one URL is slow and the rest of the site is healthy, investigate what is unique about that route before treating the entire server as overloaded.
Check whether page cache is being used
A public page that normally comes from Nginx page cache can become dramatically more expensive if every request suddenly reaches PHP and WordPress. Cache exclusions, cookies, query strings, purge behaviour or application changes can alter whether a request is cacheable.
Compare cache-hit and cache-miss behaviour rather than merely confirming that “cache is enabled”. The WordPress caching guide explains why page cache and Redis solve different problems.
PHP-FPM saturation looks different from high CPU alone
PHP-FPM has a finite number of workers. If they are all occupied, new dynamic requests wait even if another part of the server still has spare capacity.
A worker can be busy because it is using CPU, waiting on MySQL, waiting on disk, or simply waiting for a remote API to answer. Looking only at overall CPU usage can therefore miss the reason requests are queuing.
Useful PHP evidence
- PHP-FPM pool utilisation and whether the maximum worker count is being reached.
- Slow-request logs showing which PHP execution paths remain active for too long.
- Error logs for repeated fatal errors, timeouts or memory exhaustion.
- Per-site resource history where several sites share a node.
Plugins and themes are application code
A plugin can run code on every request, issue hundreds of database queries, perform remote HTTP requests or execute expensive work in wp-admin. The fact that it is installed through WordPress does not make its resource cost negligible.
Look for correlation with recent plugin/theme updates, new features, cron jobs or traffic patterns. On a production site, disabling components blindly can be disruptive; staging provides a safer place for controlled reproduction. See the staging guide.
Database problems need query evidence
High database activity can be caused by missing indexes, inefficient queries, oversized autoloaded options, lock contention, a large working set or simply too many dynamic requests reaching WordPress.
Do not assume MySQL needs more memory merely because WordPress is waiting on it. Identify slow or repeated queries and determine which application path is generating them.
Persistent Redis object caching can prevent some repeated database work, but it cannot make every query disappear and it should not be used to conceal fundamentally bad query behaviour.
External APIs can make a healthy server look slow
WordPress plugins frequently call services outside the hosting platform: payment providers, marketing systems, licence servers, analytics APIs, remote feeds and other HTTP endpoints.
A PHP worker waiting ten seconds for a remote response is still occupied for those ten seconds. Enough concurrent waits can exhaust a PHP pool while local CPU remains relatively low.
Slow logs and application traces are valuable because they can show that the delay occurs in an outbound call rather than in local PHP computation or MySQL.
WP-Cron and background work can create bursts
WordPress scheduled tasks may run housekeeping, imports, backups, queue processing, email jobs or plugin maintenance. A large job triggered by web traffic can overlap with visitor requests and create a sudden resource spike.
Look at timing. If slowdowns recur at similar intervals, scheduled work is a stronger suspect than random traffic.
Traffic quality matters, not just traffic volume
A site can be overloaded by a relatively small number of expensive uncached requests while serving a much larger volume of cached traffic easily. Login attacks, XML-RPC traffic, search endpoints, aggressive crawlers and application probes can all force dynamic work.
Separate legitimate visitors, cacheable requests and abusive or automated dynamic traffic before deciding that the site has simply “outgrown” its hosting.
502, 503 and 504 errors are clues
Gateway and service errors indicate that one layer could not obtain the expected response from another in time or at all. They are not interchangeable diagnoses.
Check the logs on both sides of the relevant boundary. Nginx may be unable to reach Apache; Apache may be unable to obtain a PHP response; PHP workers may be saturated; or a long application request may exceed a timeout. The status code narrows the investigation, but the service logs establish the cause.
Do not ignore filesystem and permissions problems
Incorrect ownership, permissions, exhausted storage, quotas or security policy can make an application fail or behave unexpectedly. A site repeatedly attempting an operation it cannot complete may also create secondary load through retries and logging.
These failures can look like application problems until the underlying platform boundary is inspected.
A practical troubleshooting order
When more hosting resources are the right answer
Sometimes the application is healthy and the workload has genuinely grown. Sustained PHP concurrency, database working set or CPU demand can justify additional or dedicated capacity.
That decision should follow diagnosis rather than replace it. The shared versus dedicated hosting guide explains when moving the infrastructure boundary makes sense.
How Webcore approaches performance troubleshooting
Webcore treats WordPress performance as a layered systems problem. Cache behaviour, Nginx and Apache request handling, PHP-FPM pools, application slow logs, Redis, MySQL and traffic patterns provide different pieces of evidence.
The objective is to identify why a request is expensive before applying a remedy. That may mean restoring cache behaviour, correcting a plugin, fixing permissions, reducing abusive traffic, resolving a database problem or adding capacity when the workload genuinely requires it.
See Managed WordPress Hosting, the Webcore Platform, or talk to Webcore if you need help diagnosing a production site.