Fix Kubernetes Pod Stuck in Pending: "0/3 nodes are available: 3 Insufficient cpu"

intermediate☸️ Kubernetes2026-03-18| Kubernetes 1.20+, kubectl CLI, any cloud provider (GKE, EKS, AKS) or on-premise cluster

Error Message

0/3 nodes are available: 3 Insufficient cpu
#kubernetes#scheduling#resources#node

What's happening

Your pod has been sitting in Pending state for a while. When you check with kubectl describe, you see something like this:

Events:
  Type     Reason            Age   From               Message
  ----     ------            ----  ----                -------
  Warning  FailedScheduling  30s   default-scheduler  0/3 nodes are available: 3 Insufficient cpu.

The Kubernetes scheduler checked all 3 nodes. None had enough free CPU to satisfy your pod's request. So it gave up and left the pod waiting.

This is different from CrashLoopBackOff (pod starts but crashes) or ImagePullBackOff (can't pull the image). Here the pod never even starts β€” it's stuck at scheduling, before any container runs.

Reproduce and diagnose

Step 1: Confirm the error

kubectl describe pod <pod-name> -n <namespace>

Scroll to the Events section at the bottom. You'll see the FailedScheduling warning:

0/3 nodes are available: 3 Insufficient cpu.

Step 2: Check what CPU your pod is requesting

kubectl get pod <pod-name> -n <namespace> -o jsonpath='{.spec.containers[*].resources}'

Or look directly at your Deployment YAML:

resources:
  requests:
    cpu: "2000m"   # ← this is what the scheduler uses to find a node
  limits:
    cpu: "4000m"

The scheduler uses requests, not limits, to make placement decisions. A request of 2000m means each node must have 2 full cores free β€” that's a lot to ask.

Step 3: Check actual node capacity and allocatable CPU

kubectl describe nodes | grep -A 5 'Allocatable\|Allocated resources'

For a cleaner view:

kubectl get nodes -o custom-columns=NAME:.metadata.name,CPU:.status.allocatable.cpu,MEMORY:.status.allocatable.memory

Then drill into each node to see what's already allocated:

kubectl describe node <node-name> | grep -A 10 'Allocated resources'

Example output:

Allocated resources:
  (Total limits may be over 100 percent, i.e., no guarantee)
  Resource           Requests     Limits
  --------           --------     ------
  cpu                1850m (92%)  3200m (160%)
  memory             1Gi (55%)    2Gi (110%)

At 92% allocated, a new pod requesting even 200m won't fit. There's simply no room left.

Solutions

Option 1: Reduce your pod's CPU request (quick fix)

Most of the time, the request is just set too high. Lower it to something realistic for what the app actually uses at startup.

resources:
  requests:
    cpu: "100m"    # reduced from 2000m
    memory: "256Mi"
  limits:
    cpu: "1000m"
    memory: "512Mi"

A common mistake: setting requests.cpu: "2" (2 full cores) when the app peaks at 200m. The limit can stay high. The request just needs to be an honest estimate of typical usage β€” not worst-case, not aspirational.

Apply the change:

kubectl apply -f your-deployment.yaml

Option 2: Scale up the cluster (add nodes)

Sometimes the request really is correct and you just need more capacity. Adding nodes is the direct fix.

GKE:

gcloud container clusters resize <cluster-name> \
  --node-pool <pool-name> \
  --num-nodes 5 \
  --region <region>

EKS (managed node group):

aws eks update-nodegroup-config \
  --cluster-name <cluster-name> \
  --nodegroup-name <nodegroup-name> \
  --scaling-config minSize=2,maxSize=10,desiredSize=5

On-premise: provision a new VM and join it to the cluster with kubeadm join.

Option 3: Enable Cluster Autoscaler

Cloud users have a smarter option: Cluster Autoscaler. It automatically provisions new nodes whenever the scheduler can't place a pod β€” no manual intervention required.

# Check if autoscaler is already running
kubectl get pods -n kube-system | grep cluster-autoscaler

Not installed? Deploy it (example for GKE with Workload Identity):

kubectl apply -f https://raw.githubusercontent.com/kubernetes/autoscaler/master/cluster-autoscaler/cloudprovider/gce/examples/cluster-autoscaler-autodiscover.yaml

Then annotate your node group so the autoscaler knows it's eligible to scale.

Option 4: Evict or scale down other workloads

Find out what's eating CPU across the cluster:

kubectl top nodes
kubectl top pods --all-namespaces --sort-by=cpu | head -20

Idle or over-replicated deployments are often the culprit. Scale them down to free up space:

kubectl scale deployment <other-deployment> --replicas=1 -n <namespace>

Option 5: Check for a LimitRange applying large defaults

A pod with no resources block gets a zero request from Kubernetes β€” that won't cause this error on its own. But a LimitRange in the namespace can inject a large default automatically.

kubectl get limitrange -n <namespace>
kubectl describe limitrange <name> -n <namespace>

Set explicit requests in your pod spec to override whatever the LimitRange is injecting.

Verify the fix

Once you've applied the change, watch the pod live:

kubectl get pods -n <namespace> -w

You should see: Pending β†’ ContainerCreating β†’ Running β€” usually within a minute or two.

Confirm no more scheduling failures:

kubectl describe pod <pod-name> -n <namespace> | grep -A 10 Events

No FailedScheduling events means you're done.

Lessons learned

  • Set realistic requests, not worst-case ones. The scheduler makes real placement decisions based on requests. Requesting 4 cores when you use 200m wastes reserved capacity on every single node in the cluster.
  • Requests and limits do different jobs. requests = what the scheduler reserves at placement time. limits = the hard ceiling enforced at runtime. Keep requests low and realistic; set limits at the actual max you'd tolerate.
  • kubectl top nodes shows usage, not allocation. A node can show 30% CPU usage but have 95% CPU requested. The scheduler works off requests, not real-time usage. Always check kubectl describe node and look at the Allocated resources section β€” that's the number that matters.
  • Cluster Autoscaler pays for itself fast. If you're on cloud infrastructure and hit this error more than once, autoscaler eliminates the manual bottleneck entirely. Set it up before you need it.

Related Error Notes