Skip to main content
DevOps Insightsguides & answers

Docker Hub · troubleshooting

You have reached your pull rate limit

Docker Hub limits how many images can be pulled without a paid account, counted per IP address for anonymous pulls, and you went over. Authenticate every pull with docker login or an imagePullSecret, then cut repeat pulls with a mirror or cache. Check your remaining allowance with one HEAD request, which does not count.

First published

New to this? Read what is actually happening first, then come back to the steps.

On this page · 9 sections

Before you start

  • The failing command's output, from docker pull, a CI job or kubectl describe pod.
  • A Docker Hub account and a personal access token, to authenticate pulls.
  • curl and jq, to read your current limit.

Run this first

step 1 of 2
TOKEN=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimitpreview/test:pull" | jq -r .token)
curl -s --head -H "Authorization: Bearer $TOKEN" https://registry-1.docker.io/v2/ratelimitpreview/test/manifests/latest | grep -i ratelimit

Look for ratelimit-limit (the allowance and window in seconds) and ratelimit-remaining

Docker's documented check. HEAD returns the limit headers without counting as a pull.

Work out which cause you have

A few questions to narrow the list. Every answer ends in a command that confirms or rules the cause out — this cannot see your cluster, so nothing here is a certainty until you have checked.

Narrow it down

0 answered · nothing is sent anywhere

Does the error mention pull rate limit and increase-rate-limits?

Cause space

3 of 3 still possible

  • Pulls are anonymous and share one addressCommon
  • The same images are pulled again and againCommon
  • A bare 429 from the abuse limitRare

Nothing ruled out yet. Answer the question above and the branches your answer eliminates will strike through here.

Or diagnose it manually

In this order. The first command usually contains the whole answer.

  1. Step 1

    TOKEN=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimitpreview/test:pull" | jq -r .token)
    curl -s --head -H "Authorization: Bearer $TOKEN" https://registry-1.docker.io/v2/ratelimitpreview/test/manifests/latest | grep -i ratelimit

    Docker's documented check. HEAD returns the limit headers without counting as a pull.

    Look for ratelimit-limit (the allowance and window in seconds) and ratelimit-remaining

  2. Step 2

    docker info --format '{{.RegistryConfig.Mirrors}}'

    Shows whether the daemon already uses a mirror.

    Look for An empty list means every pull goes to Docker Hub

Every cause, and how to fix it

Ordered by how often each one turns out to be the answer.

Pulls are anonymous and share one address

Common

CI runners, Kubernetes nodes or a whole office pull without logging in, and all of them leave through the same public IP, so they share one anonymous allowance.

Confirm

TOKEN=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:ratelimitpreview/test:pull" | jq -r .token)
curl -s --head -H "Authorization: Bearer $TOKEN" https://registry-1.docker.io/v2/ratelimitpreview/test/manifests/latest | grep -i ratelimit

ratelimit-remaining: 0, or close to it, for your address. HEAD does not count as a pull.

Fix

  • Authenticate every pull with a Docker Hub account: docker login -u USER with a personal access token on build machines.
  • In GitHub Actions, add docker/login-action with the token from a secret before any step that pulls.
  • In Kubernetes, create a docker-registry Secret for docker.io and reference it from imagePullSecrets (or from the namespace's service account), so the kubelet pulls as you.
kubectl create secret docker-registry dockerhub --docker-server=https://index.docker.io/v1/ --docker-username=USER --docker-password=TOKEN -n NAMESPACE

Then add imagePullSecrets: [{name: dockerhub}] to the pod spec or the service account.

The same images are pulled again and again

Common

Fresh CI runners, autoscaled nodes or imagePullPolicy: Always pull the same base images every time. Multi-architecture images can count once per architecture. Even an authenticated Personal account runs out.

Confirm

kubectl get pods -A -o jsonpath='{range .items[*]}{range .spec.containers[*]}{.imagePullPolicy}{" "}{.image}{"\n"}{end}{end}' | sort | uniq -c | sort -rn | head

Many Always pulls of Docker Hub images, or tags such as latest that force a fresh pull

Fix

  • Put a pull-through mirror in front of Docker Hub and point the daemons at it with registry-mirrors in /etc/docker/daemon.json; only Docker Hub can be mirrored this way.
  • Copy the base images you depend on into your own registry, or pull Docker Official Images from another registry that publishes them, such as public.ecr.aws/docker/library/.
  • Use IfNotPresent with pinned tags or digests, so a node that already has the image does not pull it again.

A bare 429 from the abuse limit

Rare

A separate limit applies to all requests from one address, whatever the account, in the order of thousands a minute. It returns 429 Too Many Requests without the pull-limit message, and authenticating does not lift it.

Confirm

docker pull IMAGE 2>&1 | tail -2

429 Too Many Requests with no mention of pull rate limit or increase-rate-limits

Fix

  • Find what is sending so many requests: a crash-looping job, a script polling tags, a misconfigured autoscaler.
  • Spread the load or serve it from a mirror; Docker notes that third-party platforms pulling for many users from one address can hit this even when authenticated.

Understanding it properly

Skip this if you are mid-incident — the working part of the page is above. Worth reading afterwards, because understanding the mechanism is what stops the next one.

In plain terms

Docker Hub lets anyone download public images, but caps how many each user can download in a window of time. If you are not logged in, the cap is shared by everything behind your public IP address: every CI job, every Kubernetes node, every colleague in the office. Once it runs out, Docker Hub answers with this message until the window moves on. Logging in gives you your own, larger allowance.

Words used on this page

Pull
Docker Hub counts a manifest download. A multi-architecture image counts once for each architecture pulled. A version check that downloads nothing does not count.
Pull rate limit
The number of pulls allowed per window: per user when authenticated, per IPv4 address or IPv6 /64 when anonymous.
Abuse rate limit
A separate limit on all requests to Docker Hub, in the order of thousands a minute per address. It returns a bare 429 Too Many Requests.
Registry mirror
A pull-through cache in front of Docker Hub, so repeat pulls are served locally and Docker Hub sees one.
What is actually happening

Docker's documentation, read on 21 Oct 2026, lists the limits per 6 hours: 100 for unauthenticated users per IPv4 address or IPv6 /64 subnet, 200 for an authenticated Personal account, and unlimited for Pro, Team and Business, all subject to fair use.

The registry reports the limit that actually applies in response headers. On 21 Oct 2026, the documented anonymous check returned ratelimit-limit: 100;w=3600, a 3,600-second window, not the 21,600 seconds the documentation shows. Read your own headers rather than either number.

Anonymous pulls are counted per address, so everything behind one NAT gateway, office network or CI egress IP shares one allowance. That is why a cluster or a busy CI system hits it while one developer never does.

When the limit is hit, Docker Hub answers the manifest request with 429 and You have reached your pull rate limit. You may increase the limit by authenticating and upgrading. A bare 429 Too Many Requests is the separate abuse limit.

How to tell this is your problem
WhereWhat you see
docker pull or docker buildtoomanyrequests: You have reached your pull rate limit. You may increase the limit by authenticating and upgrading: https://www.docker.com/increase-rate-limits
kubectl describe podFailed to pull image … 429 Too Many Requests … toomanyrequests, and the pod goes to ImagePullBackOff
TimingPulls that worked all morning start failing during a busy hour, then work again later

How to know it is actually fixed

  • The pull succeeds, and the check above shows ratelimit-remaining going down for your account rather than for your address, or no ratelimit headers at all on a paid plan.
  • Repeat pulls through the mirror no longer change ratelimit-remaining.

Stopping it happening again

  • Authenticate pulls everywhere from the start: build machines, CI and clusters.
  • Run a pull-through mirror or keep copies of base images in your own registry, so Docker Hub is not on the critical path of every deploy.
  • Pin images by tag or digest and avoid imagePullPolicy: Always for images that do not change.

Security considerations

  • Authenticate with a personal access token scoped to read, not your account password, and store it as a CI secret or a Kubernetes Secret, never in the image or the repository.
  • A shared token used by every pipeline is one leak away from someone else using your allowance; give each system its own token so it can be revoked alone.

Sources

Behaviour described here is drawn from official documentation. Where a figure could not be confirmed on an official page it is attributed in the text rather than stated as canonical.

Did this get you to an answer?

No text box on purpose — please do not paste production logs anywhere

Something wrong or out of date? Report it