Your page cache is working exactly as designed. That is the problem. A page cache turns a logged-out visit into a static file handed over in a few milliseconds, and it deliberately refuses to do that for anyone holding a login cookie. So the moment someone signs in — a customer, an editor, a subscriber, you — every request goes the long way: full PHP bootstrap, plugins loaded, theme loaded, database queried, HTML assembled from scratch.
That means logged-in speed is not a caching problem and no caching setting will fix it. It is decided by three things: how fast your server executes PHP, whether your object cache survives between requests, and how many PHP processes can run at once before requests start queuing. Those are hosting properties, not plugin settings. If your front page scores well and your account area crawls, you are looking at a server that is fast at serving files and slow at running code.
What changes the moment someone logs in
WordPress sets a wordpress_logged_in_* cookie at login. Every serious page cache — WP Rocket, LiteSpeed Cache, FlyingPress, Varnish configurations, Cloudflare’s WordPress rules — treats the presence of that cookie as an instruction to bypass the cache entirely. This is correct behaviour. Cached HTML is shared between everyone who receives it, and logged-in pages contain things that must not be shared: a name in the header, an order history, a cart, a nonce, an admin bar.
So the request path changes completely:
| Step | Logged-out (cached) | Logged-in (bypassed) |
|---|---|---|
| PHP starts | No — often served before PHP is reached | Yes, every request |
| Plugins loaded | No | All active plugins, every request |
| Theme and templates run | No | Yes |
| Database queried | No | Dozens to hundreds of queries |
| Occupies a PHP worker | No | Yes, for the whole render |
| Typical origin work | Read one file | 50–400 ms of PHP and SQL, before any network time |
The practical consequence is the one most people miss: a cached site and an uncached site can share identical hardware and feel completely different, because for logged-out traffic the hardware barely matters. Caching hides a slow server from your visitors and from your monitoring. It does not hide it from your staff or your customers.
Which WordPress pages can never be served from cache
Some of these are obvious. Others are pages site owners assume are cached and are not.
- Everything under
/wp-admin/— the entire editing and store-management experience. - WooCommerce cart, checkout and My Account — per-session by definition.
- Any page for a logged-in user, including your otherwise-cacheable blog posts and category pages.
- POST requests — form submissions, logins, add-to-cart, comment posting.
admin-ajax.phpand most REST endpoints — invoked constantly by plugins and by the block editor.wp-cron.php— scheduled work, which on most sites fires on real visitor requests.- Search results and pages with query parameters — frequently excluded by default, including by WordPress’s own speculative loading.
Worth knowing: WordPress core added speculative loading in 6.8, which prefetches a link when a visitor starts clicking it. The core defaults are prefetch with conservative eagerness, and it is disabled entirely when users are logged in, and never applies to wp-admin. So the one meaningful speed feature WordPress shipped recently does nothing at all for the traffic this article is about.
Why “enable caching for logged-in users” usually isn’t the fix
Most caching plugins offer this, and it is a reasonable option for a narrow case. WP Rocket’s User Cache, for instance, creates a separate set of cache files for each logged-in user. For a membership site or an e-learning platform where thousands of users see a near-identical dashboard, that can help.
The caveats are real, and they are documented by the vendor rather than discovered by you:
- Cache files multiply per user. A thousand logged-in users means a thousand sets of files, which consumes disk and makes cache clearing slow.
- Several optimisations stop applying to logged-in users, including cache preloading, link preloading, removing unused CSS, and asynchronous CSS loading. You trade one set of optimisations for another.
- Shared-cache workarounds exist, where all logged-in users get the same cached files. This is how one customer ends up seeing another customer’s name or cart. The vendor’s own documentation warns that content gets misplaced easily.
- It does nothing for the first visit by each user, nothing for POST requests, nothing for wp-admin, and nothing for a store where every page genuinely differs.
For a WooCommerce store the answer is closer to: do not try. Cart and checkout must be computed. The fix is to make computing them fast.
Why your monitoring insists the site is fast
This is the part that causes the most confused support tickets. Google’s field data comes from the Chrome User Experience Report, and CrUX only includes pages that are publicly discoverable — they must return a 200 and must not carry a noindex directive, the same indexability bar a search engine applies — and that are visited often enough to be statistically meaningful. Pages behind a login do not qualify.
So the Core Web Vitals report in Search Console, the field data in PageSpeed Insights, and every tool built on CrUX are reporting on your logged-out traffic only. Your LCP can sit comfortably under the 2.5-second “good” threshold at the 75th percentile while your checkout takes four seconds, and nothing in those reports will ever tell you. The same applies to most uptime and speed monitors, which fetch pages anonymously.
If you want to know what logged-in users experience, you have to measure it while logged in.
How to measure your own logged-in TTFB
Export your session cookies from a logged-in browser session, then time the request from the command line. This measures server work and strips out everything the browser does afterwards:
curl -o /dev/null -s -b cookies.txt \
-w "dns: %{time_namelookup}s\nconnect: %{time_connect}s\nttfb: %{time_starttransfer}s\ntotal: %{time_total}s\n" \
"https://example.com/my-account/"
Run it five or six times and ignore the first result. Then run the identical request without -b cookies.txt and compare. The difference between those two ttfb numbers is the cost of being logged in on your current host — and it is the single most useful number in this whole discussion, because it is the part caching can never remove.
A rough read on the result: under 200 ms of uncached TTFB is a well-tuned stack. Between 200 and 500 ms is normal and liveable. Above about 800 ms, with the browser’s own work still to come on top, you are over budget before rendering starts. For reference, WPHoster publishes an average TTFB of 350 ms and an average WooCommerce checkout of 0.55 s across its platform — our own published platform figures, not an independent benchmark of your site.
If that gap is where your problem lives, it is worth reading how WPHoster approaches the pages caching can’t help — the stack is built around uncached request speed rather than cache hit rates.
The three things that actually decide logged-in speed
1. PHP execution speed
Every uncached request is PHP executing your theme and plugins. Two factors dominate: the PHP version and whether opcode caching is properly configured. Run a current PHP release — WordPress 7.1 supports PHP 7.4 through 8.5, and the newer branches are meaningfully faster on real WordPress workloads than 7.4. If you are still on 7.4 because a plugin once broke, that decision is costing you on every single logged-in page view.
Beyond the version, CPU matters in a way it never does for cached traffic. Shared and heavily oversubscribed environments give you a fraction of a core under contention, and PHP execution is the one thing that cannot be cached away.
2. A persistent object cache
This is the most commonly missing piece. WordPress’s object cache is, by default, non-persistent: it lives in memory for the duration of a single request and is thrown away at the end of it. Install nothing, and every logged-in page view re-runs the same option lookups, the same term queries, the same user-meta reads that the previous request just ran.
Adding Redis or Memcached with an object cache drop-in changes that. Query results survive between requests, and the database stops answering the same questions thousands of times an hour. On a plugin-heavy site or a store with a large catalogue, this is usually the largest single improvement available for logged-in and admin pages — and it does nothing whatsoever for cached logged-out traffic, which is exactly why it gets overlooked.
3. PHP workers
A PHP worker is one process that can handle one request at a time. Cached requests do not need one. Every uncached request occupies one for its entire duration. When all workers are busy, further requests queue, and queue time is added to everyone’s TTFB.
The arithmetic is unforgiving. If an uncached page takes 400 ms and you have four workers, your ceiling is roughly ten uncached requests per second — and that budget is shared between customers at checkout, staff in wp-admin, admin-ajax.php calls, REST requests and cron. Hosts rarely publish worker counts, which is precisely why “unlimited visitors” can coexist with a store that stalls when three people check out while someone edits a product.
The admin traffic nobody counts
One more drain, easy to overlook because no visitor generates it. WordPress’s Heartbeat API sends a POST to admin-ajax.php on a regular pulse — roughly every 15 seconds while someone is editing a post, and less often on other screens. Each pulse is uncacheable, requires a full WordPress bootstrap, and occupies a worker.
With a handful of people in wp-admin that is background noise. With fifty staff accounts open all day, it is hundreds of uncacheable requests per minute competing with your customers for the same workers. On a busy store, Heartbeat plus the editor’s own REST traffic can be a meaningful share of total PHP work — and none of it appears in any front-end speed report.
What to check before you blame your host
In this order, because the cheap checks sometimes find it:
- Measure logged-in versus logged-out TTFB with the curl command above. Get the actual number before changing anything.
- Check whether a persistent object cache is active. Site Health reports this, and if it says a persistent object cache should be used, that is your first move.
- Check your PHP version. If it is below 8.0, plan the upgrade.
- Install Query Monitor and open a slow logged-in page. It shows query counts, the slowest queries, and which plugin owns them. A single plugin running an uncached query on every page load is a common culprit.
- Count HTTP requests your server makes to other servers during a page load — licence checks, external APIs, feeds. These block the render and no amount of hardware fixes them.
- Ask your host how many PHP workers your plan has, and what happens when they are saturated. The quality of the answer tells you a great deal.
If steps 2 through 5 come back clean and your uncached TTFB is still high, the remaining variable is the machine. That is the point at which this stops being a configuration problem.
The short version
Caching makes your public pages fast and tells you nothing about the rest of your site. Logged-in users, your store’s checkout and your own admin all take the uncached path on every request, where speed comes down to PHP execution, a persistent object cache and enough workers to avoid queuing. Measure that path specifically, because the standard reports exclude it by design.
If your uncached numbers are the problem and you have already ruled out the plugin-level causes, that is the specific thing WPHoster’s platform is built for — NVMe bare metal, Redis object caching and current PHP, with the first month at $1 so you can run the same curl comparison on real hardware before committing.