Load your slowest page and measure time to first byte separately from total load time. If the first byte takes longer than about a second, the problem is on the server. If the first byte arrives quickly and the page still crawls, the problem is what the page is carrying, and no hosting plan will move that number.
That split decides your afternoon. Get it wrong and you can spend a year paying every month for capacity you were never short of in the first place.
Start With One Number
A slow page is slow in one of three places. The server that builds the HTML, the network that carries it, or the browser that assembles it once it arrives. Time to first byte is the boundary marker between the first two and the third, which is why it is the measurement to take before any other.
You already have the tool. curl ships with macOS, with every Linux distribution, and with Windows 10 and later, and its -w flag prints a timing breakdown that no browser shows you as plainly:
curl -o /dev/null -s -w "dns: %{time_namelookup}\ntcp: %{time_connect}\ntls: %{time_appconnect}\nttfb: %{time_starttransfer}\ntotal: %{time_total}\n" https://example.com/your-slowest-page
Run it three or four times and take the middle result, because the first run pays for a cold DNS cache. Every variable in that list is documented in the curl manual under --write-out.
Google's guidance on time to first byte puts the good threshold at 0.8 seconds. I treat anything under half a second as finished business and anything over 1.5 seconds as the only thing worth working on that day, because a page cannot start rendering before its HTML arrives and every downstream optimization is built on top of that wait.
How to Read the Timing Breakdown
The numbers are cumulative, not individual. time_appconnect includes the TCP connect that came before it, so you subtract to get the cost of each stage.
| Reading | What it actually covers | A bad number points at |
|---|---|---|
time_namelookup |
Resolving the hostname | Your DNS provider, or a very long record chain |
time_connect minus namelookup |
One network round trip to the server | Physical distance, or a saturated link |
time_appconnect minus connect |
The TLS handshake, two more round trips | Distance again, amplified |
time_starttransfer minus appconnect |
The server thinking | Your application, your database, or contention |
time_total minus starttransfer |
Downloading the HTML document | An enormous HTML file, rare but real |
The fourth row is the one people mean when they say the server is slow. Everything above it is geography and plumbing.
Here is the pattern that catches most people out. A page with tcp: 0.180 and ttfb: 0.240 has a fast server sitting a long way away, because the server spent only 60 milliseconds producing the page and the rest went into getting there and back. A page with tcp: 0.020 and ttfb: 1.900 has the opposite problem. Same total, opposite fix, and you cannot tell them apart from the total alone.
If Time to First Byte Is Bad, Whose Fault Is It?
Two tests separate your own code from your neighbors on the machine.
The first is a clock test. Run the same curl command at your busiest hour, then again at four in the morning. A server-side wait that doubles during your peak and settles overnight is contention: your requests are queueing behind other work, and the fix is more capacity or fewer requests reaching PHP. A wait that measures the same at both times is your application doing something expensive on every single page load, and a bigger machine only makes the same bad query finish slightly sooner.
The second test is a cache test. Append a junk query string, something like ?cachebust=91, and time that. Most caching layers treat a unique query string as a new URL and hand the request through to your application, so the gap between the cached and uncached timings tells you how much work your site does when the cache misses. If your homepage returns in 90 milliseconds cached and 2.4 seconds uncached, every first-time visitor and every crawler is getting the 2.4 second version.
Slow database work is the usual answer. One unindexed query on a table that has grown for four years, run once per page view, will produce exactly this signature. Enable your database's slow query log for an hour and read what lands in it.
When the pattern is contention rather than code, the post on telling whether a site has outgrown shared hosting walks through the symptoms that make a capacity ceiling genuine, including the resource errors and the admin-slower-than-front-end tell. Read that before you order anything.
The Distance Problem Nobody Measures
Look at time_connect again. Subtract the DNS lookup and what remains is one round trip between you and the server, and that number has a floor set by physics rather than by software.
A round trip inside the same metropolitan area runs in single-digit milliseconds. Across an ocean it runs closer to 150. Count how many a first visit needs: one for TCP, two more for the TLS handshake, then one to request the page and receive the first byte. Four round trips before a single byte of your HTML exists in the browser. At 150 milliseconds each, that is 600 milliseconds gone and the server has not started working yet.
Nothing you install fixes that. Not a caching plugin, and not a faster processor either. The only two fixes are to move the origin closer to the people who visit it or to put a cached copy near them, and the first one is free at the point you choose a plan. BestPaidHosting sells its accounts against a named data center region for that reason, as most hosts with more than one location do: picking the wrong continent is a decision you keep paying for on every request, and correcting it later means a migration.
Check your analytics for where your visitors actually are before you assume. A local business serving one city has an easy answer.
When the Server Is Fine and the Page Is Still Slow
This is the majority case. By a wide margin.
Open your browser's developer tools, switch to the Network panel, tick "Disable cache", and reload. Chrome's network panel reference documents everything on that screen, but three readings carry most of the answer. Sort by the Size column and look at the largest three files. Read the request count and the transferred total in the summary bar along the bottom. Then hover the first row in the waterfall and find "Waiting for server response", which is the same measurement curl just gave you, now confirmed inside a real browser on a real connection.
What usually turns up:
- A hero image at 3 MB, exported at full camera resolution and displayed at 800 pixels wide. This is the single most common finding, and re-exporting it as WebP takes four minutes.
- Web fonts in four weights and two families, each one blocking text from painting until it arrives.
- A video embed that pulls in half a megabyte of player JavaScript on a page nobody watches the video on.
- Third-party tags nobody audits: a chat widget, two analytics suites, and a heatmap recorder somebody installed for a redesign years ago and never took out.
None of those are hosting problems. Every one of them is downloaded over the visitor's connection and executed on the visitor's processor, which is a machine you are not renting and cannot upgrade. For the vocabulary search engines use to score all of this, the post on Core Web Vitals and which one to fix first covers the three metrics and the order to work through them.
The Upgrade Trap
The failure mode is predictable. A site feels slow, the owner asks a forum, somebody says shared hosting is the problem, and a VPS gets ordered. The site loads at almost exactly the same speed on the new server, because the 3 MB hero image is still 3 MB and the fourteen third-party scripts are still fourteen.
The symptom pattern that tells the two apart is not subtle once you look for it. A front-end problem is boringly consistent. It takes the same eight seconds at four in the morning as it does at your busiest hour, whether one person is on the site or fifty, and the slowness lands after the page has already begun appearing on screen. A server problem swings instead: acceptable when the site is quiet, poor under load, and the browser holds a blank white screen for the whole wait rather than drawing the page in pieces.
Blank screen for two seconds, then everything at once, means the server. Content appearing in stages over eight seconds means the page.
My honest opinion after watching this go wrong repeatedly: if you have not run a timing measurement, do not buy anything. The measurement takes two minutes and the wrong upgrade costs money every month for as long as you keep it, which for most people turns out to be years.
From Measurement to Action
| What you measured | Layer | What to do |
|---|---|---|
| TTFB under 0.5 s, page still slow | Browser | Compress the images, then cut third-party scripts |
TTFB fine, time_connect over 100 ms |
Network | Move the origin nearer your audience, or cache at the edge |
| TTFB bad only at peak hours | Server, contention | Add caching first, then more capacity if it persists |
| TTFB bad at every hour | Server, your code | Find the slow query or the expensive plugin |
| TTFB fine cached, terrible with a cache-busting query string | Server, your code | Same, and check what your cache is actually covering |
| TTFB bad after the application is already tuned | Server, real ceiling | Semi-dedicated hosting or a VPS |
One row is a hosting purchase. It sits at the bottom because the rows above it are the ones you can finish this week, with your own hands, without a migration or a new bill, and because a site that has been through them arrives at the capacity conversation with numbers instead of a hunch.
Your Next Twenty Minutes
Run the curl command against your slowest page, once now and once during your busiest hour. Add a third run with a cache-busting query string on the end. Write the three time-to-first-byte figures somewhere you will find them again, because they are the only evidence you will have when a support agent or a forum tells you to buy something.
All three under half a second means the server has already done its job, so close the hosting tab and open the Network panel instead. A peak-hour figure that stands out from the other two is a capacity conversation, and you now have a real number to bring to it rather than a feeling. Bad across the board points at your own application, and on WordPress the post on what WordPress hosting needs to do well sorts out which parts of that belong to the host and which stay yours.
Measure first. The number tells you where to spend, and it is almost never where you assumed.