DevOps

How to fix ImagePullBackOff in Kubernetes — 5 real causes

Every real reason ImagePullBackOff happens and the exact kubectl commands to diagnose + fix each one. No fluff.

ImagePullBackOff is the K8s error you’ll hit within your first week. Pods stay in ImagePullBackOff status. Nothing runs. Docs give generic advice.

Here are the 5 REAL causes ranked by frequency + the exact fix for each.

First, diagnose (30 seconds)

kubectl get pods

The status column immediately shows the problem:

Then:

kubectl describe pod <pod-name>

Scroll to Events: at bottom. The last event message tells you which of the 5 causes below you’re hitting:

kubectl describe pod Events section showing Pulling, Failed, ErrImagePull, and ImagePullBackOff events

For a broader view of what’s happening across the cluster:

kubectl get events --sort-by='.lastTimestamp'

The events output shows the exact pull failure and its reason — often more useful than pod-level output alone:

kubectl get events showing pull failures with the exact error message from the daemon

Cause 1 (60% of cases) — typo in image name

Failed to pull image "nginc:latest": pull access denied

You typed nginc not nginx. Or mysql:8.4.2 when the tag is 8.4. Or redis:latest-alpine (that tag doesn’t exist).

Fix: check the exact image name on Docker Hub:

docker pull <image-name>:<tag>

If Docker fails locally, K8s will fail too.

Cause 2 (20% of cases) — private registry, no credentials

Failed to pull image: unauthorized: authentication required

The image is on a private registry (Docker Hub private repo, ECR, GCR, or company registry). K8s doesn’t have credentials.

Fix: create a docker-registry secret + reference it in the pod spec:

kubectl create secret docker-registry regcred \
  --docker-server=<registry-url> \
  --docker-username=<user> \
  --docker-password=<pass> \
  --docker-email=<email>

Then in the Deployment:

spec:
  template:
    spec:
      imagePullSecrets:
      - name: regcred
      containers:
      - name: myapp
        image: private-registry.com/myapp:1.0

Cause 3 (10% of cases) — image exists but tag doesn’t

Failed to pull image "myapp:v2": manifest for myapp:v2 not found

Image myapp exists on the registry, but tag v2 was never pushed.

Fix: check what tags actually exist. On Docker Hub, browse to the image page → “Tags” tab. From CLI:

docker manifest inspect myapp:v2

If the manifest lookup fails, the tag doesn’t exist on the registry.

Cause 4 (5% of cases) — rate limits (Docker Hub)

Failed to pull image: toomanyrequests: You have reached your pull rate limit

Docker Hub limits anonymous pulls to 100/6 hours per IP. K8s cluster hitting that = pulls fail.

Fix: authenticate to Docker Hub even for public images (raises limit):

kubectl create secret docker-registry dockerhub-cred \
  --docker-server=https://index.docker.io/v1/ \
  --docker-username=<user> \
  --docker-password=<personal-access-token> \
  --docker-email=<email>

Reference it via imagePullSecrets in your pods.

Cause 5 (5% of cases) — network/DNS to registry blocked

Failed to pull image: net/http: TLS handshake timeout

K8s nodes can’t reach the registry (corporate firewall, air-gapped cluster, misconfigured DNS).

Fix: SSH into a node → try docker pull <image> manually. If it fails, check node’s DNS + firewall. Common corporate fixes:

  • Add registry mirror config
  • Use an internal registry
  • Whitelist the registry hostname on firewall

Prevention

  • Always pin image tags — never use :latest in production (unpredictable + breaks caching)
  • Use image digests for prod: myapp@sha256:abc123... (immutable, guaranteed same content)
  • Set up a private registry for internal images (Harbor / ECR / GCR)
  • Enable image scanning (Trivy, Snyk) before deploying

The 30-second debug flow

Every ImagePullBackOff, run this:

kubectl describe pod <pod-name> | grep -A5 Events
kubectl get events --sort-by='.lastTimestamp' | tail -20

Read the error message. Match to the 5 causes above. Apply matching fix.

Rarely-mentioned gotcha

Image name is CASE SENSITIVE. MyApp:1.0 and myapp:1.0 are treated as different images. Always use lowercase for consistency.

What NOT to do

  • Don’t restart pods hoping it “just works”
  • Don’t recreate the deployment — same YAML = same error
  • Don’t blame the cluster — 95% of these are your image name

The error is deterministic. Fix the input, output changes.

Recommended

DevOps YAML Pack

36 production-ready configs — Kubernetes, Docker Compose, GitHub Actions, Terraform, Helm, Ansible. Every file heavily commented. Copy, paste, ship.

Get the pack — ₹499 →
Never miss an article