LearnDevOpsHands-On Labs
Troubleshooting Matrix/toomanyrequests: You have reached your pull rate limit
LinuxHigh Severity

toomanyrequests: You have reached your pull rate limit

Fix Docker Hub "toomanyrequests: You have reached your pull rate limit": run docker login, or pull via an ECR pull-through cache or a registry mirror.

Observed Error Signature / Log Pattern
Error response from daemon: toomanyrequests: You have reached your pull rate

Incident Overview

Fix Docker Hub "toomanyrequests: You have reached your pull rate limit": run docker login, or pull via an ECR pull-through cache or a registry mirror.

medium fix·6 min read

By Vishvesh Patel·DevOps Engineer·Updated 16 September 2026

BASHDiagnostic / remediation command
Error response from daemon: toomanyrequests: You have reached your pull rate
limit. You may increase the limit by authenticating and upgrading:
https://www.docker.com/increase-rate-limit

Failed to pull image "nginx:latest": rpc error: code = Unknown desc = failed
to pull and unpack image "docker.io/library/nginx:latest": failed to copy:
httpReadSeeker: failed open: unexpected status code 429 Too Many Requests

Do this first3 steps

Run these in order. Each one tells you what its output means before you change anything.

• Confirm it is the limit and see what is left

If even this fails you are already at zero. Anonymous pulls are counted per source IP, so an entire NAT'd cluster or CI fleet shares one budget and exhausts it far faster than any one person would.

• Authenticate, which gets you your own budget

An authenticated account is counted per user instead of per IP, which alone resolves most cases. On Kubernetes create a docker-registry secret and attach it to the service account rather than to each Pod.

• Stop depending on Docker Hub for the durable fix

Then move base images behind a pull-through cache. ECR, Artifactory or a registry mirror. A cluster that pulls the same base image on every node is the thing actually burning the quota.

Docker Hub limits how many image pulls an anonymous client can make, counted per IP address over a rolling six hours. Authenticated free accounts get a higher allowance, and paid accounts higher still.

The per-IP part is why this bites CI and not your laptop. A shared NAT gateway, a Kubernetes node pool or a CI runner fleet all appear as one or a handful of addresses, so the whole team's pulls count together, and a cluster scaling up pulls the same base image once per node.

It is also why the error arrives suddenly with no change on your side: someone else exhausted the shared budget.

BASHDiagnostic / remediation command
docker run --rm curlimages/curl -s https://auth.docker.io/token?service=registry.docker.io\&scope=repository:library/nginx:pull | head -c 80

Confirm it is the rate limit

In Kubernetes it surfaces as ImagePullBackOff with a 429 in the events:

Check what your current allowance looks like:

w=21600 is the six-hour window in seconds. Three pulls left.

BASHDiagnostic / remediation command
docker pull nginx:latest

Fix 1: Authenticate (five minutes)

The cheapest improvement, and it changes the counter from your shared IP to your account.

In GitHub Actions:

Use an access token, not your password. It can be scoped to read-only and revoked independently.

For Kubernetes, create a pull secret and attach it to the default service account so every pod in the namespace benefits without editing each manifest:

That patch is per namespace, so repeat it wherever you deploy, and note that pods already running are unaffected until they next pull.

BASHDiagnostic / remediation command
docker login -u myuser

Fix 2: Pull from somewhere else (ten minutes)

Many common images are mirrored on registries with no such limit:

mirror.gcr.io is a drop-in read-through mirror of Docker Hub's library images, which makes it the lowest-effort change of all. Prefix the image name and nothing else moves.

Official images for most languages and databases are also published to public.ecr.aws, GitHub Container Registry (ghcr.io) and Quay.

BASHDiagnostic / remediation command
# Docker Hub
FROM nginx:1.27-alpine

# Amazon ECR Public, no rate limit for AWS-authenticated pulls
FROM public.ecr.aws/nginx/nginx:1.27-alpine

# Google mirror of Docker Hub
FROM mirror.gcr.io/library/nginx:1.27-alpine

Fix 3: ECR pull through cache (best fix on AWS)

If you are on AWS, this is the one worth doing properly. ECR caches upstream images on first pull and serves every subsequent pull from your own registry:

Three benefits beyond the rate limit: pulls stay inside AWS so they are faster and incur no internet data transfer, images survive upstream deletion, and ECR image scanning applies to them.

The --credential-arn points at a Secrets Manager secret holding Docker Hub credentials, which raises the upstream allowance for the cache's own fetches.

BASHDiagnostic / remediation command
aws ecr create-pull-through-cache-rule \
  --ecr-repository-prefix dockerhub \
  --upstream-registry-url registry-1.docker.io \
  --credential-arn "$SECRET_ARN"

Fix 4: A registry mirror for the cluster

Configure the container runtime on every node to route Docker Hub pulls through a mirror, so no manifest changes at all:

Listing the upstream second means a cache miss still works. Apply it through your node bootstrap or a DaemonSet so new nodes inherit it. A mirror configured by hand on existing nodes disappears the next time the group scales.

For a self-hosted option, a pull-through registry:2 or Harbor instance does the same and keeps everything inside your network.

BASHDiagnostic / remediation command
# /etc/containerd/config.toml
[plugins."io.containerd.grpc.v1.cri".registry.mirrors."docker.io"]
  endpoint = ["https://mirror.gcr.io", "https://registry-1.docker.io"]

Fix 5: Pull less

Worth doing regardless of the above.

Pin tags. FROM node:latest re-pulls whenever the tag moves; FROM node:22.11.0-alpine is cached far more often.

Cache images in CI. A build that pulls the same base image on every run is wasting both allowance and time. Use your CI's Docker layer cache, or pull once into a self-hosted runner.

Set imagePullPolicy deliberately. Always on a pinned tag pulls on every pod start for no benefit:

Note that Kubernetes defaults to Always when the tag is latest, which is one more reason not to use it.

Use multi-stage builds so you are not pulling a large base for the final image.

BASHDiagnostic / remediation command
imagePullPolicy: IfNotPresent

A checklist

Frequently Asked Questions

Why am I hitting Docker Hub's rate limit when I have barely pulled anything?

Because anonymous pulls are counted per IP address, not per user. A CI runner fleet, a Kubernetes node pool, or an office behind one NAT gateway all present as a small number of addresses, so everyone's pulls share the same budget, and a cluster scaling up pulls the same base image once per node. That is also why the error appears suddenly with nothing changed on your side: somebody else exhausted the allowance.

How do I check how many pulls I have left?

Request a token for any library image and read the response headers: ratelimit-limit and ratelimit-remaining, with w=21600 indicating the six-hour rolling window. It is worth doing before assuming the limit is the cause, since a 429 can also come from an upstream proxy. Authenticating changes which counter you are measured against, so run the check with and without credentials to confirm the login is taking effect.

How do I authenticate Docker Hub pulls in Kubernetes?

Create a docker-registry secret with your username and an access token, then patch it onto the namespace's default service account as an imagePullSecrets entry, that way every pod in the namespace uses it without editing individual manifests. The patch is per namespace, so repeat it wherever you deploy. Pods already running keep their current images until they next pull, so the change is not immediately visible.

What is the ECR pull through cache and why is it the best fix?

A rule that makes your own ECR registry a transparent cache in front of an upstream registry: the first pull of an image fetches it from Docker Hub, and every pull after that is served from ECR. You reference images by their ECR path, so the rate limit stops applying entirely. It also keeps pulls inside AWS, faster and no internet data transfer cost, protects you from upstream deletions, and brings the images into ECR's image scanning.

Can I avoid Docker Hub without changing every image reference?

Yes, two ways. Prefix images with mirror.gcr.io/library/, Google's read-through mirror of Docker Hub library images, which is a one-word change per reference. Or configure a registry mirror in containerd on every node, so docker.io pulls are transparently routed elsewhere and no manifest changes at all. List the upstream registry second in the mirror endpoints so a cache miss still succeeds, and apply the config through node bootstrap so new nodes inherit it.

Does imagePullPolicy affect the rate limit?

Significantly. Always makes the kubelet contact the registry on every pod start even when the image is already on the node, which on a busy cluster multiplies your pull count for no benefit. Set IfNotPresent with pinned tags so an image already present is reused. Note that Kubernetes silently defaults to Always when the tag is latest, which is one more reason to pin versions rather than relying on it.

Reference and practice

Learn the underlying concept

Other Docker errors

Free, comprehensive DevOps tutorials and learning roadmaps. Master Docker, Kubernetes, CI/CD, and more.

Get notified about new tutorials and features.

• Roadmaps

• Interview Prep

• Certifications

• Company

© 2026 DevOpsLesson. All rights reserved.

Need to practice this scenario?

Simulate this error condition and practice recovery commands safely in our in-browser terminal.

Open Linux Sandbox