How to Tell If Your Host Is Throttling Your Site

How to Tell If Your Host Is Throttling Your Site

If your site suddenly answers every request in roughly the same sluggish time no matter how light the page is, and that floor holds steady while your own server logs show almost no traffic, deliberate host throttling is a strong candidate. Host throttling detection is mostly about finding a limit that behaves like a wall: a fixed ceiling on CPU, memory or bandwidth that your account hits and then sits against, rather than the variable delays you get from real load or slow code.

The key distinction is between resource exhaustion and resource capping. Exhaustion rises and falls with demand. A cap is flat. When you plot response time against request rate, an exhausted machine shows a curve that climbs gradually and gets noisy near the top. A throttled account shows a sharp knee and then a plateau, because once the limiter engages the host stops giving you more of whatever you asked for. Everything below assumes you have shell access to the server or at least the ability to run timed requests against it.

Measure the shape of the delay before you blame anyone

Start with timing, not with support tickets. Run the same request many times and look at the distribution, not the average. Averages hide bimodal behaviour, which is exactly what a limiter produces: fast responses while you are under the cap, then a distinct second cluster at the throttled rate.

for i in $(seq 1 20); do
  curl -o /dev/null -s -w '%{time_starttransfer} %{time_total}\n' \
    https://example.com/health
done

You want the time to first byte, which is time_starttransfer, separated from total time. If the first byte is fast and the body then crawls, the delay is in transfer, which points at bandwidth shaping. If the first byte itself is slow and consistent, the application process is being starved or held, which points at CPU or process limits. Run the loop once against a static file and once against a dynamic endpoint. A limiter that only bites on dynamic requests is a CPU or process cap. One that bites on static files too is bandwidth or connection shaping.

Read the headers the host sends back

Throttling is often announced, just quietly. Rate limiters and proxies frequently attach headers, and some hosts expose their own accounting. Ask for the response headers and read them rather than guessing.

curl -sI https://example.com/ | grep -iE \
  'retry-after|x-ratelimit|server|via|cf-|x-cache'

A Retry-After header on a response that is not a redirect or a maintenance page is close to a confession. So is a 429 status appearing in a loop that your own logs never recorded, because a 429 generated by the host's edge never reaches your application. Compare the status codes your application logs against the status codes curl observes. Any gap is traffic being handled, and possibly rejected, before it reaches you. Via and cache headers tell you how many intermediaries sit in front of your origin, which matters because the limiter may live at any of them.

Look for the limiter in the configuration

On a virtual private server or a container you control, the cap is usually visible. Check the cgroup limits, because those are what the kernel actually enforces.

cat /sys/fs/cgroup/cpu.max
cat /sys/fs/cgroup/memory.max
systemd-cgtop --order=cpu

A finite cpu.max means your processes are being scheduled against a quota, and sustained work will be throttled once the quota is spent within each period. The kernel counts this, and you can read the counter directly. If the throttled time keeps climbing while your own CPU usage looks modest, the quota is the constraint, not your code. On shared hosting you will not have these files, which is itself informative: you cannot see the limit because you do not control the layer where it is applied.

Bandwidth shaping is separate and shows up in the interface statistics and in tc rules if you have the privileges to read them. If you do not, compare a transfer from your server to a fast external endpoint against the same transfer to a second endpoint. A host cap produces near identical rates to both, which no amount of internet weather would do.

Separate throttling from slow code and real traffic

Before you conclude anything, rule out the boring explanations. Profile the application under a load you generate yourself, using a local client, so the network path is short and the request rate is under your control. If response time is flat and fast at low concurrency and then hits a hard ceiling, you have found a limit. If it degrades smoothly, you have found a bottleneck in your own stack, and the fix is caching, indexes or query work, not a conversation with the host.

Watch for the telltale sign of a limiter engaging on a schedule rather than on load. Throttling that begins at a fixed interval, or that resets at a fixed interval, is almost never caused by organic traffic. Correlate the slow windows against your access log volume. If the slow periods do not line up with the busy periods, load is not the cause. Also check whether the throttled behaviour follows your account rather than your server: if a second site on the same account slows at the same moment, the limit is applied to the account as a whole.

One more check that costs nothing is to watch the connection itself. A host that limits concurrent connections will accept the TCP handshake and then stall before responding. Time the phases separately with curl using time_connect, time_appconnect, time_starttransfer and time_total. A fast connect followed by a long pause before the first byte is a queue, and a queue that appears at a fixed concurrency regardless of how simple the request is points to a connection or worker limit rather than to your application.

What to do with what you find

Write down the evidence before you act on it: the command you ran, the times you saw, and the point at which the behaviour changed. Hosts respond far better to a short, specific report than to a complaint that the site is slow. Ask directly which limits apply to your plan, whether they are per account or per process, and whether any of them are enforced at a layer you cannot see. If the limits are real and the plan cannot be changed, the practical options are to reduce what you ask of the server through caching and static generation, to move the heavy work off the request path, or to move to a plan whose limits match your workload. The measurements tell you which of those is worth doing.

Related articles

Subscribe to our newsletter

Get the latest hosting tips, performance insights, and industry news.