Fix Kubernetes ResourceQuota Exceeded: pods is forbidden: exceeded quota

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

Error Message

Error from server (Forbidden): pods "my-pod" is forbidden: exceeded quota: my-quota, requested: cpu=500m, used: cpu=900m, limited: cpu=1
#kubernetes#resourcequota#quota#namespace#resource-limit

The Error

Error from server (Forbidden): pods "my-pod" is forbidden: exceeded quota: my-quota, requested: cpu=500m, used: cpu=900m, limited: cpu=1

Your namespace has a ResourceQuota cap, and this pod pushed it over. The error message spells out the math: quota limit is 1000m CPU, 900m is already claimed, and you're requesting 500m more β€” that's 1400m total. Kubernetes rejects it outright.

The pod never enters Pending state. It gets blocked at the API server before the scheduler even sees it.

Step 1: Check the Current Quota Usage

Start by seeing exactly what's consumed versus what's allowed:

# Replace 'my-namespace' with your actual namespace
kubectl describe resourcequota -n my-namespace

Output looks like:

Name:       my-quota
Namespace:  my-namespace
Resource    Used   Hard
--------    ----   ----
cpu         900m   1
memory      512Mi  2Gi
pods        8      10

CPU is the culprit here β€” 900m used out of a 1000m hard limit. Only 100m left, nowhere near enough for a pod requesting 500m.

To scan quotas across all namespaces at once:

kubectl get resourcequota --all-namespaces

Step 2: Find What's Consuming the Quota

Before touching anything, identify which pods are eating up that 900m:

kubectl get pods -n my-namespace -o custom-columns=NAME:.metadata.name,CPU:.spec.containers[*].resources.requests.cpu

Got metrics-server installed? kubectl top shows actual usage, not just declared requests:

kubectl top pods -n my-namespace

Watch for the mismatch. A pod requesting 500m CPU but averaging 30m in practice is a prime right-sizing target.

Step 3: Fix Options

Option A β€” Reduce the Pod's Resource Request

Inflated requests are the most common culprit. If the pod doesn't genuinely need 500m, dial it down in your manifest:

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
  namespace: my-namespace
spec:
  containers:
  - name: my-container
    image: my-image:latest
    resources:
      requests:
        cpu: "100m"      # was 500m, reduced to 100m
        memory: "128Mi"
      limits:
        cpu: "200m"
        memory: "256Mi"

Run kubectl top pods first to pick a realistic value. Setting requests to 100m for a pod that averages 80m gives a safe buffer without wasting quota.

Option B β€” Increase the ResourceQuota Limit

Sometimes the namespace just needs more headroom. Check the current quota definition first:

kubectl get resourcequota my-quota -n my-namespace -o yaml

Patch it directly:

kubectl patch resourcequota my-quota -n my-namespace \
  --type='json' \
  -p='[{"op": "replace", "path": "/spec/hard/cpu", "value": "2"}]'

Or, if you manage quotas as YAML files (the recommended approach), update and apply:

apiVersion: v1
kind: ResourceQuota
metadata:
  name: my-quota
  namespace: my-namespace
spec:
  hard:
    cpu: "2"        # increased from 1 to 2
    memory: 4Gi
    pods: "20"
kubectl apply -f resourcequota.yaml

Option C β€” Delete Unused Pods or Scale Down Deployments

Completed and failed pods still count against the quota until deleted. Clean up the graveyard:

# Delete completed/failed pods
kubectl delete pods -n my-namespace --field-selector=status.phase==Succeeded
kubectl delete pods -n my-namespace --field-selector=status.phase==Failed

# Scale down a deployment that's no longer needed
kubectl scale deployment old-deployment -n my-namespace --replicas=0

Worth checking before anything else β€” a namespace full of stale Completed jobs can quietly hold hundreds of millicores. You might free up enough quota without touching the limit at all.

Step 4: Verify the Fix

Once you've made your changes, confirm the quota has headroom before retrying:

# Check updated quota usage
kubectl describe resourcequota -n my-namespace

# Try creating the pod again
kubectl apply -f my-pod.yaml

# Confirm it's running
kubectl get pod my-pod -n my-namespace

Expected output:

NAME     READY   STATUS    RESTARTS   AGE
my-pod   1/1     Running   0          10s

Tips for Next Time

  • Always set resource requests and limits β€” namespaces with ResourceQuota reject pods that have no requests/limits defined at all. Use a LimitRange to set namespace-wide defaults if you don't want to specify them on every pod.
  • Pair LimitRange with ResourceQuota β€” LimitRange sets per-container defaults; ResourceQuota caps the namespace total. They're designed to work together.
  • Gate your CI/CD on quota checks β€” add a pre-deploy step that runs kubectl describe resourcequota -n $NAMESPACE and fails the pipeline if available CPU drops below your deployment's request size.
  • Base requests on real metrics, not guesses β€” use kubectl top pods or pull a week of p95 CPU data from Prometheus. That's a far better input than "500m sounds about right."
  • Quota is policy, not physics β€” this error means you've hit an administrative cap, not a physical resource shortage. The node may have plenty of free CPU. ResourceQuota is purely a governance limit set by your cluster admin.

Related Error Notes