All articles
Tutorials

How to Fix the "ImagePullBackOff" Error in Kubernetes

Learn how to diagnose ImagePullBackOff with kubectl describe, fix wrong image tags and private registry auth, and verify pods reach Running state.

How to Fix the "ImagePullBackOff" Error in Kubernetes cover
8 min read

TL;DR

  • ImagePullBackOff means the kubelet cannot pull the container image and is retrying with exponential backoff. ErrImagePull is the failed attempt; ImagePullBackOff is the waiting state between retries.
  • The fix always starts with kubectl describe pod and the Events section. The error string there maps directly to the cause: wrong tag, missing imagePullSecrets, rate limit, or network failure.
  • Wrong image name or tag is the fastest fix: correct spec.containers[].image, then restart the workload.
  • Private registries need a kubernetes.io/dockerconfigjson Secret referenced in spec.imagePullSecrets or on the ServiceAccount.
  • After any fix, confirm with kubectl get pods showing Running and 1/1 Ready.

You merged a Deployment, ran kubectl get pods, and every replica is stuck in ImagePullBackOff. The rollout looks green in GitOps, but nothing is serving traffic. You open the dashboard, see a red pod, and still do not know whether the image name is wrong, the registry password expired, or the cluster lost network access to Docker Hub.

In this article, you will reproduce the failure in a sandbox namespace, read the exact error from pod Events, fix the two most common causes (bad image reference and missing registry credentials), and verify the pod reaches Running with screenshots at each step.

Note

What you need: kubectl 1.28+, access to a cluster (kind, minikube, EKS, GKE, or AKS), and permission to create namespaces, Secrets, and Deployments in a non-production sandbox. The walkthrough uses namespace demo-app.

Why pods get stuck in ImagePullBackOff

Kubernetes schedules the pod onto a node. The kubelet asks the container runtime (containerd or CRI-O) to pull the image from the registry in spec.containers[].image. When that pull fails, you see ErrImagePull on the first attempts. After repeated failures, the kubelet backs off and the pod status becomes ImagePullBackOff.

That status does not mean the pod crashed. It means the image never arrived. The application container never started.

StatusWhat it means
ErrImagePullA pull attempt failed right now
ImagePullBackOffPull failed; kubelet is waiting before the next retry
InvalidImageNameMalformed image string in the pod spec
ImageInspectErrorRuntime could not inspect the image after pull

Most production incidents fall into four buckets:

Error pattern in EventsTypical causeFix
not found / manifest unknownWrong repository or tagCorrect the image field
unauthorized / authentication requiredMissing or bad imagePullSecretsCreate or update registry Secret
toomanyrequestsDocker Hub anonymous rate limitAuthenticate with pull Secret
i/o timeout / no such hostDNS, firewall, or registry outageFix network path to registry

How to read the error in pod Events

Do not guess from the Deployment YAML alone. Start with the pod status, then read Events.

Deploy a deliberately broken image so you can see the failure state. This manifest references a tag that does not exist on Docker Hub:

broken-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
  namespace: demo-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
      - name: api
        image: nginx:does-not-exist-2026
        ports:
        - containerPort: 80

Create the namespace and apply the manifest:

kubectl create namespace demo-app
kubectl apply -f broken-deployment.yaml

List pods until the status shows ImagePullBackOff:

kubectl get pods -n demo-app -w

You should see output like this:

kubectl get pods showing ImagePullBackOff status for the api pod in demo-app namespace

Describe the pod and scroll to Events. The Failed line contains the registry error string you need:

kubectl describe pod -n demo-app -l app=api
kubectl describe pod Events section showing ErrImagePull and manifest not found for nginx:does-not-exist-2026

In this example, not found means the tag does not exist. The fix is not to restart the node. It is to correct the image reference.

How to fix a wrong image name or tag

Confirm the image exists before you change the cluster. For public images on Docker Hub:

docker pull nginx:1.25-alpine

If that fails locally, the tag is wrong or the registry is unreachable from your network.

Patch the Deployment to a valid image:

fixed-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
  namespace: demo-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      containers:
      - name: api
        image: nginx:1.25-alpine
        ports:
        - containerPort: 80

Apply the fix and restart the rollout so new pods pull immediately:

kubectl apply -f fixed-deployment.yaml
kubectl rollout restart deployment/api -n demo-app
kubectl rollout status deployment/api -n demo-app

Watch the pod transition to Running:

kubectl get pods -n demo-app
kubectl get pods showing Running status and 1/1 Ready after the image tag fix

If the pod still shows ImagePullBackOff, describe it again. A typo in the new tag produces the same error string with a different image name.

How to fix private registry authentication

When the Events line says unauthorized or authentication required, the image reference is probably correct but the cluster has no credentials for a private registry.

Run kubectl describe pod on the failing workload. The Events section for a missing pull Secret looks like this:

Events:
  Type     Reason     Age   From     Message
  ----     ------     ----   ----     -------
  Warning  Failed     21s   kubelet  Failed to pull image "registry.example.com/api:v2": rpc error: code = Unknown desc = failed to pull and unpack image "registry.example.com/api:v2": failed to resolve reference "registry.example.com/api:v2": pull access denied, repository does not exist or may require authorization: server message: unauthorized: authentication required

Create the registry pull Secret

Replace the registry host, username, and password with your values. The Secret must live in the same namespace as the pod.

kubectl create secret docker-registry regcred \
  --docker-server=registry.example.com \
  --docker-username=ci-bot \
  --docker-password='YOUR_TOKEN' \
  --docker-email=ci-bot@example.com \
  -n demo-app

Verify: kubectl get secret regcred -n demo-app shows type kubernetes.io/dockerconfigjson.

Attach the Secret to the workload

Reference the Secret in the pod spec (or on the ServiceAccount every pod in the namespace uses):

deployment-with-pull-secret.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: api
  namespace: demo-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: api
  template:
    metadata:
      labels:
        app: api
    spec:
      imagePullSecrets:
      - name: regcred
      containers:
      - name: api
        image: registry.example.com/api:v2
        ports:
        - containerPort: 80

Apply and restart:

kubectl apply -f deployment-with-pull-secret.yaml
kubectl rollout restart deployment/api -n demo-app

Verify: kubectl describe pod -n demo-app -l app=api shows Pulled and Created events without unauthorized.

Patch the ServiceAccount when many Deployments share a namespace

Attaching the Secret to the default ServiceAccount avoids repeating imagePullSecrets in every manifest:

kubectl patch serviceaccount default -n demo-app \
  -p '{"imagePullSecrets": [{"name": "regcred"}]}'

Verify: kubectl get sa default -n demo-app -o yaml lists regcred under imagePullSecrets.

Warning

Rotating registry tokens requires recreating the Secret (kubectl delete secret regcred then create again) or using a secrets operator. Updating only the Deployment image does not refresh expired credentials.

How to verify the pod is healthy

A fixed pull ends with three signals:

  1. Pod phase: kubectl get pods -n demo-app shows STATUS = Running and READY = 1/1.
  2. Events: kubectl describe pod shows Pulled, Created, and Started without new Failed pull events.
  3. Application check: Port-forward or hit the Service to confirm the process responds:
kubectl port-forward -n demo-app deployment/api 8080:80
curl -I http://127.0.0.1:8080

You should receive an HTTP response from Nginx (or your application health endpoint).

When these fixes do not apply

ImagePullBackOff is always an image delivery problem, but not every delivery problem is a wrong tag or missing Secret.

  • Self-signed registry TLS: The runtime may reject the certificate before auth runs. You need CA trust configured on nodes (containerd certs.d or cluster-specific registry config), not only an imagePullSecrets entry.
  • imagePullPolicy: Never with a missing local image: The kubelet will not pull from a registry. The image must already exist on the node under the exact name.
  • Architecture mismatch: Pull succeeds but the container fails to start with exec format error. That is a different failure mode after pull; fix the image build target platform.
  • Air-gapped clusters: No route to public registries. Mirror images to an internal registry and update all manifests to that host.

For container networking after the pod is running, see Docker ports vs expose for how port publishing differs between Docker and Kubernetes Service types.

For authoritative reference, see the Kubernetes docs on pulling an image from a private registry and debugging pods.

Frequently asked questions

Share𝕏

Writer

  • Ilyas Rufai

    Technical content writer and DevSecOps specialist focused on cloud-native security and developer experience

Need help with your technical content?

We help B2B SaaS teams turn complex products into clear documentation and content that developers actually use.

Book a call
How to Fix ImagePullBackOff in Kubernetes | Reclear