1. Docktor
  2. Guides
  3. Docker CPU throttling: how to tell

Docker CPU throttling: how to tell

A container can be slow while the host looks idle, because its CPU quota ran out. Here is how throttling works and how to confirm it.

Updated October 6, 2026

What CPU throttling is

When you give a container a CPU limit, such as cpus: "1.5" in a Compose file, Docker turns it into a CPU quota in the container’s cgroup. The quota is a number of microseconds the container may run in each scheduling period, which is 100,000 µs (100 ms) by default. A limit of 1.5 CPUs becomes 150000 100000 in cpu.max.

The container can use several cores at once, but their combined run time per period is capped. When the budget is spent, its processes are paused until the next period. That pause is throttling. It happens even when the host has plenty of idle CPU, which is why it is easy to miss: the host looks fine and the app is slow.

Symptoms

  • Requests are slower or spikier than expected, while host CPU is low.
  • The service’s CPU use sits flat at its limit during busy periods.
  • Latency gets worse under load but recovers quickly when load drops.

docker stats reports CPU use, but it doesn’t tell you whether the container was held back by its limit. The throttling counters do.

Check it by hand

On a cgroup v2 host, go to the container’s cgroup (see Monitor Docker Compose over SSH for finding it) and read two files:

cat cpu.max
# 150000 100000   -> quota and period in microseconds ("max 100000" = no limit)

grep -E 'nr_periods|nr_throttled|throttled_usec' cpu.stat

The counters are cumulative since the container started, so measure a window:

grep -E 'nr_periods|nr_throttled|throttled_usec' cpu.stat
sleep 10
grep -E 'nr_periods|nr_throttled|throttled_usec' cpu.stat

Subtract the first reading from the second. If nr_throttled rose by a meaningful fraction of the rise in nr_periods, the container spent that share of the periods throttled, and throttled_usec tells you how much run time it lost. Throttling in a few periods is normal for bursty work. Sustained throttling during the slow period is the signal.

Also check pressure. A rising some value in the container’s cpu.pressure file means tasks were waiting for CPU.

What you can do about it

  • Raise the limit, if the host has capacity. Check that the host isn’t itself saturated first.
  • Remove the limit for a service that should be allowed to burst, if you accept that it can compete with its neighbors.
  • Reduce the work: fewer worker processes, cheaper requests, caching.
  • Spread the load across more replicas or hosts.

Limits usually exist for a reason, so change them knowing what they protect. Hosts on cgroup v1 use different files (cpu.cfs_quota_us and a cpu.stat with throttling counters) and have no PSI.

How Docktor reports it

Docktor’s CPU quota throttling finding looks for usage near the container’s cpu.max quota, throttling counters that are rising, and elevated CPU pressure. It names the affected service, states a confidence, and keeps what it observed separate from what it infers. For example, “web is likely limited by its CPU quota” with the evidence listed underneath. It also lists competing explanations when there are any, and says “insufficient evidence” when that is the truth. On cgroup v1 hosts it says which signals it couldn’t read and lowers its confidence.

See what’s wrong before you open a terminal.

Diagnose Docker Compose issues over SSH, with the evidence on your Mac.

Download for Mac

v0.1.0 · macOS 15+ · Apple silicon & Intel