Blog · October 28, 2026 · 14 min read

ImagePullBackOff in Kubernetes: Fixes

Graphic title card for the article “ImagePullBackOff in Kubernetes: Fixes” with a stylised motif: a container icon whose arrow to the registry ends at a barrier, next to it a clock for the wait time.
Graphic: HumanITy

ImagePullBackOff means the kubelet could not pull your Pod's container image and is waiting, with a growing delay, before it tries again. The container never starts. The cause is almost always in the events of kubectl describe pod, in the "Failed to pull image" message. The usual suspects: a wrong image name or tag, a private registry without imagePullSecrets, the Docker Hub pull rate limit, network or DNS trouble on the node, an image that doesn't ship your node's CPU architecture, and a registry certificate the node doesn't trust. ErrImagePull is a single failed attempt; ImagePullBackOff is the wait that follows.

I've been running Kubernetes clusters since 2017, today mostly k3s on Hetzner Cloud. I'm a CNCF Kubestronaut and wrote the Kubernetes Practical Guide published by Rheinwerk Computing. All my Kubernetes articles are on the Kubernetes page.

What ImagePullBackOff means in Kubernetes

Per the Kubernetes docs, a container has three possible states: Waiting, Running and Terminated. While the image is missing, it's Waiting, and the Reason field tells you why, in this case ImagePullBackOff. The Pod stays in the Pending phase, which, per the docs, includes the time spent downloading images. More on phases and states in Kubernetes Pod: What Is a Pod?.

Unlike a CrashLoopBackOff, your code never ran, so there are no logs. The answer is in the events.

ErrImagePull vs. ImagePullBackOff

Both describe the same problem at two points in time. In the kubelet source, ErrImagePull is defined as a general image pull error; you see it right after a failed attempt. Then a back-off timer starts. If the kubelet is asked for the image again while it runs, it reports ImagePullBackOff and writes the previous error into the container's Message field, shown under State: Waiting in kubectl describe pod. That's why the STATUS column in kubectl get pods flips between the two.

The Kubernetes docs cap the wait at 300 seconds, or 5 minutes. In the source, it starts at 10 seconds and doubles with each failure, so a long-stuck Pod only retries every few minutes.

A few related reasons are worth recognizing on sight:

Reason What it means
ErrImagePull an attempt to pull the image failed
ImagePullBackOff the kubelet is waiting after a failure before trying again
InvalidImageName the image name can't be parsed, usually a formatting typo
ErrImageNeverPull imagePullPolicy: Never is set and the image isn't on the node
RegistryUnavailable the container runtime reports that the registry can't be reached

Diagnosis: read kubectl describe and the events

Three commands are enough:

kubectl get pods -n shop
kubectl describe pod api-7d9c6b5f8-x2k4q -n shop
kubectl events --for pod/api-7d9c6b5f8-x2k4q -n shop

In kubectl describe pod, the container section shows State: Waiting with Reason: ImagePullBackOff. The events come at the very bottom. Schematically, shortened and with an example image, the sequence looks like this:

Events:
  Type     Reason   Message
  ----     ------   -------
  Normal   Pulling  Pulling image "registry.example.com/shop/api:1.4.2"
  Warning  Failed   Failed to pull image "registry.example.com/shop/api:1.4.2": <container runtime error>
  Warning  Failed   Error: ErrImagePull
  Normal   BackOff  Back-off pulling image "registry.example.com/shop/api:1.4.2"
  Warning  Failed   Error: ImagePullBackOff

What matters is the text after "Failed to pull image": what the container runtime got back from the registry, such as an unknown image, a denied login, a timeout or a certificate error. Match it to one of the causes below. More everyday commands are in kubectl Commands: The Essentials.

Often missed: the container runtime on the node pulls the image, not your Pod, using the node's network, DNS and certificates. Testing from another Pod tells you little. With node access, test there with crictl pull <image>, usually as root, or k3s crictl pull <image> on k3s. For a private registry, crictl ignores the imagePullSecret; pass --creds <user>:<token>, or the test fails even with a healthy registry. Without node access, docker pull <image> on your machine is the first check, and the one the Kubernetes docs suggest.

The most common causes and how to fix them

Cause Typical hint in the events Fix
wrong name or tag image or tag not found check name, tag and registry; was the image actually pushed?
private registry without credentials access denied, or FailedToRetrieveImagePullSecret create a Secret and reference it in imagePullSecrets
Docker Hub pull rate limit "You have reached your pull rate limit" pull authenticated, run your own mirror
network, DNS, proxy timeout, host can't be resolved test from the node, check proxy and firewall
wrong CPU architecture "no match for platform in manifest" build the image for the node's architecture
registry certificate TLS error during the handshake add the CA on every node

Wrong image name or tag

The Kubernetes docs name a failed image pull as the most common reason for Pods stuck in Waiting and give three checks: is the name right, was the image pushed, can you pull it by hand? Watch what Kubernetes fills in silently: busybox becomes docker.io/library/busybox:latest. Leave out the registry, and Kubernetes asks Docker Hub.

For production, the docs advise against :latest and recommend a meaningful tag such as v1.42.0 or a digest. A digest never changes; a tag can later point to a different image.

Private registry without imagePullSecrets

A private registry needs credentials. The docs recommend a Secret of type kubernetes.io/dockerconfigjson that you reference in the Pod as imagePullSecrets:

kubectl create secret docker-registry regcred -n shop \
  --docker-server=registry.example.com \
  --docker-username=<user> \
  --docker-password=<token>
spec:
  imagePullSecrets:
    - name: regcred
  containers:
    - name: api
      image: registry.example.com/shop/api:1.4.2

The Secret has to live in the same namespace as the Pod. If the events show FailedToRetrieveImagePullSecret, Kubernetes can't find a Secret with that name. Per the docs, credentials typed on the command line may end up in your shell history. So create the Secret from a file instead (kubectl create secret generic regcred --from-file=.dockerconfigjson=<path> --type=kubernetes.io/dockerconfigjson, described on the same docs page), and use a read-only token rather than your password. If every Pod in a namespace uses the same registry, attach the Secret to the Pods' ServiceAccount, usually default. New Pods with that ServiceAccount pick it up automatically, existing ones don't. More in ConfigMap and Secret in Kubernetes.

Docker Hub pull rate limit

According to the Docker docs (as of October 28, 2026), Docker Hub allows unauthenticated users 100 pulls per 6 hours per IPv4 address or IPv6 /64 subnet, and authenticated Personal accounts 200. Paid plans have no pull limit but a fair use policy. Nodes pulling anonymously through the same public IPv4 address share one allowance, and a multi-arch image counts as one pull per architecture.

Once you hit the limit, Docker Hub answers with status 429 and "You have reached your pull rate limit". The ratelimit-limit and ratelimit-remaining headers of a HEAD request show where you stand, and per Docker a HEAD request doesn't count as a pull. Fixes: pull authenticated with an imagePullSecret for https://index.docker.io/v1/, run a mirror, and use fixed tags with imagePullPolicy: IfNotPresent.

Network, DNS and proxy

If the node can't reach the registry, the error usually names the host and the network error. Typical culprits are a firewall, a proxy the container runtime doesn't know about, or a hostname the node's DNS can't resolve. In my training sessions, this happens often on company laptops: the cluster starts, the Pods stay in ImagePullBackOff, and almost always a proxy or firewall is blocking the image download. How to deal with it locally is in Local Kubernetes: A Cluster on Your Machine. Check from the node first, then the cluster.

Wrong CPU architecture

Per the Kubernetes docs, a registry can serve an image index with one image per architecture. If the node's architecture is missing, say linux/arm64 on a Raspberry Pi, containerd stops with "no match for platform in manifest". docker buildx imagetools inspect <image> shows which platforms an image has. If an image is mislabeled instead, the node pulls it, the container exits immediately, and you end up in CrashLoopBackOff. More in Kubernetes on the Raspberry Pi.

Registry certificate

If your registry uses a certificate from an internal CA, the pull fails at the TLS handshake. The CA belongs on every node: with containerd as the ca field in a hosts.toml under /etc/containerd/certs.d/<registry-host>/, which only takes effect if config_path = "/etc/containerd/certs.d" is set in the containerd configuration, in k3s as ca_file under tls in /etc/rancher/k3s/registries.yaml, followed, per the docs, by a k3s restart on each node. Switching verification off (insecure_skip_verify or skip_verify) is a quick test at most.

After the fix: wait or restart?

After the fix, the kubelet retries on its own, in the worst case only after 5 minutes. In the source, the back-off is tracked per Pod and image, so a new Pod starts without any wait. If the fix was outside the manifest (image pushed, Secret created, network fixed), delete the Pod if a Deployment recreates it, or restart it with kubectl rollout restart deployment api -n shop. If you changed the manifest, Kubernetes rolls out new Pods anyway. How rollouts behave is covered in Rolling Update and Rollback in Kubernetes.

How to prevent ImagePullBackOff

Four habits prevent most cases:

  1. Fixed tags or digests instead of :latest, so nodes don't re-pull for no reason.
  2. Credentials on the ServiceAccount, so nobody forgets the imagePullSecret in a manifest.
  3. Your own registry or a mirror for base images, independent of the Docker Hub rate limit.
  4. Builds for every architecture your nodes run, plus a pipeline check that the image with exactly that tag exists. What such a pipeline looks like is in Kubernetes CI/CD: the Pipeline.

Frequently asked questions

What does ImagePullBackOff mean?

The kubelet couldn't pull the image from the registry and is waiting before the next attempt, with a growing pause of up to 5 minutes. The container doesn't run, and the Pod stays Pending.

What's the difference between ErrImagePull and ImagePullBackOff?

ErrImagePull reports a failed attempt; ImagePullBackOff is the wait that follows. The cause is the same and sits in the events of kubectl describe pod.

How do I fix ImagePullBackOff with a private registry?

Create a Secret with kubectl create secret docker-registry in the Pod's namespace and reference it under imagePullSecrets. If you see FailedToRetrieveImagePullSecret, the name or the namespace is wrong.

Why does docker pull work on my machine but not in the cluster?

Your machine and the node differ in credentials, network, certificates and often architecture. Test on the node itself, for example with crictl pull, adding --creds for a private registry.

Where to go next

ImagePullBackOff happens before the container ever starts. If the image runs but the container keeps crashing, CrashLoopBackOff: Debugging Pods gets you out. If the kernel kills it for running out of memory, read Kubernetes OOMKilled: Detect and Fix.

Next time: kubectl describe pod, read the text after "Failed to pull image", find the cause in the table above. The fundamentals of Pods and the command line are in my Kubernetes Practical Guide (Rheinwerk Computing).

Kevin Welter

Kevin Welter

Developer, IT architect, author of technical books (Kubernetes, cloud infrastructures) and speaker. Runs his business with an AI workforce of fourteen AI employees and shows solo business owners in his community how to hire their first AI employee.

More about AI employees

Kubernetes from the basics to a production-ready cluster

Get the book