Kubernetes Pods stuck in Pending — 8 causes and exact fixes
Every reason a Pod stays in Pending status and the kubectl commands to diagnose each one. From resource limits to node selectors to PVC issues.
A Pod stuck in Pending means Kubernetes cannot schedule it onto any node. The Pod is created but no container is running. Here are the 8 real causes ranked by frequency, with exact diagnostic commands.
First — always run this
kubectl describe pod <pod-name>
Scroll to the Events: section at the bottom. The scheduler explains WHY it can’t place the Pod. Every fix below starts from this event message.
Cause 1 — Insufficient CPU or memory on nodes
Event message:
0/3 nodes are available: 3 Insufficient cpu.
The Pod requests more resources than any node has free.
Diagnose:
kubectl top nodes
kubectl describe nodes | grep -A 5 "Allocated resources"
Fix:
- Reduce Pod’s
resources.requests.cpu/memoryif over-requested - Scale cluster (add nodes)
- Free capacity by removing unused Deployments
Cause 2 — Node selector or affinity doesn’t match
Event message:
0/3 nodes are available: 3 node(s) didn't match node selector.
Pod requires nodes with specific labels but none have them.
Diagnose:
kubectl get nodes --show-labels
kubectl get pod <pod-name> -o yaml | grep -A 5 nodeSelector
Fix:
- Add the required label to a node:
kubectl label node <node> disktype=ssd - Or remove the
nodeSelectorfrom Pod spec if not needed
Cause 3 — Taints without matching tolerations
Event message:
0/3 nodes are available: 3 node(s) had untolerated taint.
Nodes have taints (e.g. NoSchedule) that Pod doesn’t tolerate.
Diagnose:
kubectl describe nodes | grep -A 2 Taints
Fix:
- Add matching toleration to Pod spec:
tolerations:
- key: "special"
operator: "Equal"
value: "true"
effect: "NoSchedule"
- Or remove the taint from node:
kubectl taint node <node> special-
Cause 4 — PersistentVolumeClaim not bound
Event message:
persistentvolumeclaim "data-pvc" not found
or
0/3 nodes are available: 3 pod has unbound immediate PersistentVolumeClaims.
Pod references a PVC that doesn’t exist or has no matching PV.
Diagnose:
kubectl get pvc
kubectl describe pvc <pvc-name>
Fix:
- Create the missing PVC
- Check StorageClass exists:
kubectl get storageclass - Verify dynamic provisioning is working (CSI driver installed)
Cause 5 — Image pull secret missing (private registry)
Event message:
Failed to pull image: unauthorized
Pod’s image is in a private registry, no credentials configured.
Diagnose:
kubectl get pod <pod-name> -o yaml | grep imagePullSecrets
kubectl get secrets | grep regcred
Fix:
kubectl create secret docker-registry regcred \
--docker-server=<registry-url> \
--docker-username=<user> \
--docker-password=<pass>
Add to Pod spec:
spec:
imagePullSecrets:
- name: regcred
Cause 6 — Pod anti-affinity conflicts
Event message:
0/3 nodes are available: 3 node(s) didn't match pod anti-affinity rules.
Pod has anti-affinity requiring separation from other Pods, but no eligible node.
Diagnose:
kubectl get pod <pod-name> -o yaml | grep -A 20 affinity
kubectl get pods -o wide
Fix:
- Add more nodes (so anti-affinity has room to spread)
- Relax anti-affinity from
requiredDuringSchedulingtopreferredDuringScheduling
Cause 7 — Namespace resource quota exceeded
Event message:
forbidden: exceeded quota
Namespace has ResourceQuota and adding this Pod would exceed limits.
Diagnose:
kubectl describe quota -n <namespace>
Fix:
- Delete unused Pods in namespace
- Increase quota:
kubectl edit quota <quota-name> - Deploy to different namespace
Cause 8 — Scheduler broken or overloaded
Rare, but happens on stressed clusters.
Diagnose:
kubectl get pods -n kube-system | grep scheduler
kubectl logs -n kube-system <scheduler-pod-name>
Fix:
- Restart scheduler pod
- Check for scheduler configuration issues
- On managed K8s (EKS/GKE), this usually resolves itself
The universal debug checklist
Copy this and run through it every time:
# Basic status
kubectl get pod <pod-name>
# Detailed events (THE most important)
kubectl describe pod <pod-name>
# Node status
kubectl get nodes
kubectl describe nodes
# Recent events across cluster
kubectl get events --sort-by='.lastTimestamp' | tail -20
# Related resources
kubectl get pvc
kubectl get storageclass
kubectl get secrets
Reproduce this yourself (browser sandbox)
Free Kubernetes playground: https://killercoda.com/playgrounds/scenario/kubernetes
Create a pod that will be Pending:
kubectl run stuck-pod --image=nginx --overrides='{"apiVersion":"v1","spec":{"nodeSelector":{"nonexistent":"label"}}}'
Then:
kubectl describe pod stuck-pod
Screenshot the Events section. Note the “didn’t match node selector” message.
Clean up:
kubectl delete pod stuck-pod
Prevention
Set sensible defaults from the start:
- Resource requests — not too high, not too low. Start with 100m CPU, 128Mi memory. Adjust based on actual usage.
- No
nodeSelectorunless truly needed. Default schedulers work well. - Test PVCs before deploying real workloads — verify storage class works.
- Use
kubectl topregularly to see node capacity trends.
Bottom line
Every Pending pod has a specific reason. The scheduler always tells you what it is via kubectl describe. Match the event message to one of the 8 causes above. Apply the corresponding fix. Done in 5 minutes.
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 →