1. Introduction

If you've deployed a workload to Kubernetes and your pod is stuck in an ImagePullBackOff state, the kubelet couldn't pull the container image it needs. The pod won't start — and it won't tell you exactly why unless you know where to look.

This guide walks through the most common causes of ImagePullBackOff and gives you a clear, ordered diagnostic process to fix it fast. Whether you're dealing with a wrong image tag, a misconfigured registry secret, or a network restriction, you'll find the cause and the fix here.

2. What ImagePullBackOff Actually Means

When Kubernetes schedules a pod, the kubelet on the assigned node attempts to pull the container image from the registry. If that pull fails, Kubernetes transitions the pod through two states:

The "BackOff" part is important. Kubernetes won't keep hammering the registry — it uses an exponential backoff strategy, which means retries get further apart over time. The pod stays in this state until the underlying issue is resolved or the pod is deleted.

3. Common Causes

4. Step-by-Step Fix

Step 1: Get the exact error message

Start by describing the pod. This gives you the actual pull error, not just the state name:

kubectl describe pod <pod-name> -n <namespace>
      # Look for the Events section at the bottom:
      # Events:
      #   Warning  Failed     2m    kubelet  Failed to pull image
      #             "myrepo/myapp:v1.2": rpc error: code = Unknown
      #             desc = failed to pull and unpack image
      #             "docker.io/myrepo/myapp:v1.2":
      #             unexpected status code 401 Unauthorized

The error code in the Events section is your primary diagnostic signal. Note it before moving to the next step.

Step 2: Verify the image reference

Check that the image name and tag in your manifest exactly match what exists in the registry.

# Check what image the pod is trying to pull kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.spec.containers[*].image}'

Common problems here:

Step 3: Check if the image exists

If the tag looks right, confirm the image actually exists in the registry:

# Docker Hub / public registry — check via CLI docker manifest inspect myrepo/myapp:v1.2
      # AWS ECR aws ecr describe-images --repository-name myapp --image-ids imageTag=v1.2
      # GCR / Artifact Registry gcloud container images list-tags gcr.io/my-project/myapp

If the image doesn't exist, fix the push step in your CI/CD pipeline before re-deploying.

Step 4: Check imagePullSecrets for private registries

If you're using a private registry (ECR, GCR, Docker Hub private, self-hosted), the node needs credentials. Check whether the pod has a pull secret configured:

kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.spec.imagePullSecrets}'
      # Expected output if secret is set:
      # [{"name":"my-registry-secret"}]
      # Check the secret exists in the correct namespace: kubectl get secret my-registry-secret -n <namespace>

If there's no pull secret, or the secret doesn't exist in the pod's namespace, that's your issue. Create one:

# For Docker Hub / generic registry kubectl create secret docker-registry my-registry-secret \   --docker-server=https://index.docker.io/v1/ \   --docker-username=<username> \   --docker-password=<password> \   --docker-email=<email> \   -n <namespace>
      # Then reference it in your pod spec or service account:
      # spec:
      #   imagePullSecrets:
      #     - name: my-registry-secret

Step 5: Validate the secret credentials

A secret can exist with stale or invalid credentials. Verify by decoding and testing manually:

# Decode the .dockerconfigjson field kubectl get secret my-registry-secret -n <namespace> \   -o jsonpath='{.data.\.dockerconfigjson}' | base64 --decode
      # You should see a JSON object with auths, username, password
      # Test the credentials by trying to pull from the same node or a local machine docker login <registry-url> -u <username> -p <password> docker pull <image>:<tag>

Step 6: Check network access to the registry

If credentials look fine, the node may not be able to reach the registry. This is common in:

To test connectivity from the node:

# Find which node the pod is scheduled on kubectl get pod <pod-name> -n <namespace> -o wide
      # SSH to the node (or use a debug pod on the same node) kubectl debug node/<node-name> -it --image=busybox
      # Inside the debug pod, test DNS + HTTPS connectivity nslookup registry-1.docker.io wget -q --spider https://registry-1.docker.io/v2/

If DNS resolves but the HTTPS request hangs or fails, check your security groups, NACLs, and any egress network policies. For ECR on EKS in a private cluster, you need a VPC endpoint for ECR (both ecr.api and ecr.dkr). For a deeper dive on ECR-specific authentication errors, see ECR Login Failed: Fix AWS ECR Authentication.

Step 7: Check for rate limiting

Docker Hub limits unauthenticated pulls to 100/6h per IP. On a busy cluster with many nodes sharing a NAT IP, this can trigger ImagePullBackOff:

# The error message will contain:
      # toomanyrequests: You have reached your pull rate limit
      # Fix: authenticate pulls even for public images
      # Create a Docker Hub pull secret (even free account significantly raises limits)
      # Or use a registry mirror / pull-through cache

5. Verification Steps

Once you've applied a fix, verify the pod recovers:

# Watch pod status in real time kubectl get pod <pod-name> -n <namespace> -w
      # Expected transition:
      # NAME       READY   STATUS              RESTARTS
      # myapp-xyz  0/1     ImagePullBackOff    0
      # myapp-xyz  0/1     Init:0/1            0
      # myapp-xyz  0/1     PodInitializing     0
      # myapp-xyz  1/1     Running             0
      # If the pod doesn't recover automatically, force a rollout: kubectl rollout restart deployment/<deployment-name> -n <namespace>

6. Common Mistakes

7. Prevention Tips

8. Summary

ImagePullBackOff means Kubernetes can't pull the container image. The fix depends on the underlying cause:

CauseFix
Wrong image tagCorrect the tag in your manifest; verify it exists in the registry
Image doesn't existPush the image first; fix your CI build/push step
No imagePullSecretCreate a docker-registry secret and reference it in the pod spec
Bad credentialsDecode the secret and verify login; recreate with valid credentials
Network / firewallCheck node-to-registry connectivity; add VPC endpoints for ECR
Rate limitingAuthenticate DockerHub pulls; use a pull-through cache

When in doubt, start with kubectl describe pod — the Events section almost always points you directly at the cause.