Short answer
Measure TTFB on the same URL cached and uncached. If both are fast, your problem is in the browser, not the server. If the uncached number is slow, it's your application. If even cached pages are slow, it's your host.
Key takeaways
- A page load has two halves — the server half (TTFB) and the browser half. Fixing the wrong one wastes months.
- The cached-versus-uncached comparison is the single most revealing test, and almost nobody runs it.
- Wildly variable readings matter more than slow ones: variance means resource contention, not an undersized plan.
- For most sites the server is fine and the front end is heavy — which is not what anyone wants to hear.
Almost every “my site is slow” thread follows the same shape. Someone posts a speed test, half the replies say switch hosts, the other half say it’s your plugins, and the original poster is no better off than before they asked.
Both camps are guessing. The question is answerable in about twenty minutes, with tools you already have, and the answer determines whether you should be spending money or spending an afternoon.
The one idea you need first
#A page load has two halves, and they have different owners.
The server half ends the moment the first byte of HTML arrives in the browser. That window belongs to your host and your application — DNS, connection setup, PHP execution, database queries. It is measured as Time to First Byte.
The browser half is everything after: downloading images, fonts, CSS and JavaScript, running scripts, painting the page. That belongs to how your site is built.
So: measure the server half first, because it is the half you can attribute cleanly.
Test 1 — Get a real TTFB number
#Speed-test websites give you one reading from one location on one day. That is not enough to conclude anything. Run this from a terminal instead:
for i in {1..5}; do
curl -o /dev/null -s -w "TTFB: %{time_starttransfer}s total: %{time_total}s\n" \
https://yourdomain.com/
done
Five readings, because a single one tells you nothing about consistency. On Windows, use the same command in WSL or Git Bash.
Read the results like this:
| Average TTFB | What it means |
|---|---|
| Under 200ms | Your server is fine. Stop looking here. |
| 200–600ms | Unremarkable. Worth improving, unlikely to be your main problem. |
| Above 600ms | Something on the server side is genuinely wrong. |
| Wildly variable | The most informative result of all — see Test 4. |
For context, every provider in our speed rankings sits under 220ms on US origin TTFB, and the fastest is 118ms. Those figures are for a well-configured site on a healthy plan. If you are seeing 1,500ms, the gap is not explained by which company you chose.
Test 2 — Cached versus uncached (the one that matters)
#This is the single most revealing measurement, and almost nobody runs it.
Request the same page twice: once so it serves from cache, once bypassing cache entirely.
Most caching plugins bypass on a query string, so ?nocache=1 usually works. Failing
that, log in — logged-in requests almost always skip the page cache.
# Cached
curl -o /dev/null -s -w "cached: %{time_starttransfer}s\n" https://yourdomain.com/
# Uncached
curl -o /dev/null -s -w "uncached: %{time_starttransfer}s\n" "https://yourdomain.com/?nocache=1"
Now read the pair together:
| Cached | Uncached | Verdict |
|---|---|---|
| Fast | Fast | Server is healthy. Your problem is the browser half. |
| Fast | Slow | Your application is slow — PHP, database, plugins. Cache is hiding it. |
| Slow | Slow | Your host is the bottleneck. Nothing in your site can fix this. |
Test 3 — Are you measuring the CDN or the server?
#If you run Cloudflare or any CDN, your speed test may be reporting how fast an edge cache answered — which says nothing about your actual server.
Check the response headers:
curl -sI https://yourdomain.com/ | grep -i "cf-cache-status\|x-cache\|age"
HIT means you measured the CDN. To measure the origin, request the server’s IP directly
with the Host header set:
curl -o /dev/null -s -w "origin TTFB: %{time_starttransfer}s\n" \
--resolve yourdomain.com:443:YOUR.SERVER.IP https://yourdomain.com/
This distinction is why our rankings report two separate TTFB columns rather than blending them into one score. A CDN can make a mediocre server look excellent in a speed test while every uncacheable page — checkout, account, admin — stays slow.
If that trade-off is your actual question, CDN or a faster server? covers it directly.
Test 4 — The consistency check
#Run Test 1 again at three different times: early morning, mid-afternoon, and evening in your server’s timezone.
Consistent numbers — even mediocre ones — mean a stable environment. Numbers that swing from 200ms to 1,400ms mean resource contention: either your plan is undersized for what you are running, or you are sharing a machine with a site that is having a busy day.
That second case is the “noisy neighbour” problem, and it is the classic argument for leaving shared hosting. You cannot optimise your way out of somebody else’s traffic. It is also increasingly caused by automated traffic rather than human visitors — see AI crawlers and your hosting.
Test 5 — The bare install
#If Tests 2 and 4 point at your host and your host disagrees, this settles it.
Install a clean WordPress site on the same plan, in a subdirectory or subdomain. Default theme. No plugins. No content. Measure its TTFB.
A bare WordPress install should respond in well under 300ms on any competent host. If your empty install is slow, the conversation is over — it is not your plugins, your theme, or your images, because you no longer have any.
Reading your results
#| What you found | What to do |
|---|---|
| Cached and uncached both fast | Ignore hosting entirely. Compress images, remove third-party scripts, defer JavaScript. |
| Uncached slow, cached fast | Profile the application. Query Monitor will show slow queries and which plugin causes them. Add object caching. |
| Both slow, consistently | Your plan or your host is undersized. Upgrade the plan first — it is cheaper than migrating. If that fails, move. |
| Both slow, wildly variable | Contention. Move to an isolated environment or a host that does not oversell. |
| Bare install slow | Move. You have proof. |
The honest caveat
#For most sites, the answer is the first row: the server is fine and the front end is heavy. That is not what people want to hear, because moving host feels like a decisive action and image compression feels like homework.
But the reverse case is real, and when it is real no amount of optimisation helps. If your uncached TTFB is above 600ms consistently, you are paying an unavoidable tax on every single page view, and the fix is a better server.
If you get there, the speed rankings compare eight managed cloud hosts on exactly the number you have just measured — US origin TTFB, no CDN assistance. Then switch hosts without losing rankings covers doing it without breaking anything, and what hosting actually costs covers not getting caught by renewal pricing on the way in.
Common questions
What is a good TTFB?
Under 200ms is good, under 100ms is excellent, and above 600ms means something is wrong. But the absolute number matters less than the gap between your cached and uncached readings — that gap is what tells you where the delay actually lives.
My TTFB is fine but my site still feels slow. Why?
Because TTFB only measures how quickly the server starts replying. Everything after that — images, fonts, JavaScript, third-party scripts — is the browser's work. A fast server cannot rescue a page carrying four megabytes of images. This is the most common case by far.
Will moving to a faster host fix my slow site?
Only if your server is genuinely the bottleneck. If your TTFB is already under 200ms, a faster host will save you a few dozen milliseconds while the actual problem — usually front-end weight — goes untouched. Diagnose before you migrate.
My host says the problem is my plugins. Are they right?
Sometimes, and there is a test that settles it. Install a clean WordPress site with a default theme and no plugins on the same plan, and measure that. If the bare install is also slow, the problem is not your plugins.