Kubernetes PVC Stuck in Pending? Here's How to Fix It (2026)
Step-by-step troubleshooting guide for PersistentVolumeClaims stuck in Pending state — covering StorageClass issues, provisioner problems, capacity limits, and access mode mismatches.
PVC stuck in Pending is one of those errors that looks simple from the outside — "just give the pod its storage" — but can be caused by half a dozen different things, and the error messages are rarely specific enough to tell you which one.
Here is a systematic guide to diagnosing and fixing PVCs that refuse to bind.
Step 1: Check the PVC Status and Events
kubectl describe pvc my-pvc -n your-namespaceThe Events section is where all the useful information lives. Common messages you might see:
no persistent volumes available for this claim and no storage class is set
no persistent volumes available for this claim and its StorageClass does not exist
waiting for a volume to be created either by the external provisioner or manually
Each of these points to a different root cause.
Root Cause 1: No StorageClass Specified and No Default
The most common cause for freshly set-up clusters or claims migrated from another cluster.
# Check if a default StorageClass exists
kubectl get storageclassLook for the (default) annotation in the output:
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION
gp3 (default) kubernetes.io/aws-ebs Delete WaitForFirstConsumer true
If nothing is marked as default, any PVC without an explicit storageClassName will hang in Pending forever.
Fix option 1: Add a default annotation to an existing StorageClass:
kubectl patch storageclass gp3 \
-p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'Fix option 2: Specify the StorageClass explicitly in your PVC:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
storageClassName: gp3 # Explicit — does not rely on default
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10GiRoot Cause 2: StorageClass Does Not Exist
# Check what StorageClasses exist
kubectl get storageclass
# Your PVC is requesting one that is not listed
kubectl get pvc my-pvc -o jsonpath='{.spec.storageClassName}'If the StorageClass name in the PVC does not match any existing StorageClass, you need to either create the StorageClass or fix the PVC to use an existing one.
This commonly happens when moving from one cluster to another — the new cluster has different provisioner names. For example, old cluster had gp2, new cluster has gp3.
Root Cause 3: Provisioner Not Running
The StorageClass exists but the CSI driver or external provisioner that backs it is not running.
# Check the provisioner name
kubectl get storageclass gp3 -o jsonpath='{.provisioner}'
# Output: kubernetes.io/aws-ebs or ebs.csi.aws.com
# For EBS CSI driver on EKS — check if the driver pods are running
kubectl get pods -n kube-system | grep ebs-csi
# For generic CSI drivers
kubectl get pods -n kube-system | grep csiIf the provisioner pods are in CrashLoopBackOff or not present at all, the StorageClass cannot fulfill PVCs regardless of configuration.
On EKS, the EBS CSI driver must be installed as an add-on:
aws eks create-addon \
--cluster-name my-cluster \
--addon-name aws-ebs-csi-driver \
--service-account-role-arn arn:aws:iam::123456789:role/AmazonEKS_EBS_CSI_DriverRoleRoot Cause 4: VolumeBindingMode = WaitForFirstConsumer
This is not a bug — it is expected behavior that confuses people.
kubectl get storageclass gp3 -o jsonpath='{.volumeBindingMode}'
# Output: WaitForFirstConsumerWhen VolumeBindingMode is WaitForFirstConsumer, the PVC will stay in Pending until a Pod that uses it is also pending or scheduled. This is intentional — it ensures the volume is created in the same availability zone as the pod.
If no pod is consuming this PVC yet, the PVC will stay in Pending. This is normal.
# Check if there is a pod waiting on this PVC
kubectl get pod -o json | grep -A 5 "claimName: my-pvc"
# Confirm by checking pod events
kubectl describe pod my-pod
# Events should show: waiting for a volume to be provisionedThe fix is not to change the storage class — it is to deploy the pod that needs the PVC. Once a pod claims the PVC, provisioning will begin.
Root Cause 5: Access Mode Mismatch
If you have an existing PersistentVolume (PV) that you expect the PVC to bind to, access mode mismatch is a common cause of Pending.
# Check PV access modes
kubectl get pv
# Check PVC access modes
kubectl get pvc my-pvc -o jsonpath='{.spec.accessModes}'Common mismatches:
- PVC requests
ReadWriteManybut PV only supportsReadWriteOnce(EBS volumes can only beReadWriteOnce) - PVC requests
ReadWriteOncebut the PV was already created with a different mode
For EBS/EBS CSI: these disks only support ReadWriteOnce. If you need ReadWriteMany, you need EFS (for AWS) or equivalent shared storage.
Root Cause 6: Storage Capacity Exhausted
Less common but possible — the cluster has run out of provisioning capacity for the requested storage class in the requested zone.
kubectl describe pvc my-pvc
# Look for: "no available capacity" or "failed to provision"For EBS on EKS, this is rare but can happen in heavily used AZs. Moving the workload to a different AZ or using a different volume type usually resolves it.
Quick Diagnosis Flowchart
PVC stuck in Pending
↓
kubectl describe pvc → check Events
↓
"no storage class" → set default StorageClass or specify storageClassName
↓
"StorageClass does not exist" → fix storageClassName in PVC
↓
"waiting for volume" → check CSI driver pods are running
↓
VolumeBindingMode: WaitForFirstConsumer → deploy the consuming pod
↓
Access mode mismatch → fix accessModes to match PV / use appropriate storage type
↓
Still stuck → check provisioner logs: kubectl logs -n kube-system -l app=ebs-csi-controller
Checking Provisioner Logs
When nothing else explains it:
# EBS CSI controller logs
kubectl logs -n kube-system \
-l app=ebs-csi-controller \
-c csi-provisioner \
--tail=50
# General provisioner events
kubectl get events -n your-namespace --sort-by='.lastTimestamp' | tail -20The provisioner logs often contain the actual error from the cloud API — permission denied, quota exceeded, invalid parameter — that explains exactly what is failing.
More Kubernetes storage troubleshooting? Check our Kubernetes OOMKilled fix guide and Kubernetes evicted pods disk pressure fix.
Today I Fixed
Short real fixes from production — posted daily
Stay ahead of the curve
Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.
Related Articles
Kubernetes PVC Stuck in Pending — Every Cause and Fix (2026)
Your PersistentVolumeClaim is stuck in Pending and your pod won't start. Here's every reason this happens and exactly how to fix it.
ArgoCD App of Apps Not Syncing — Every Fix (2026)
Your ArgoCD App of Apps pattern stopped syncing. Child apps aren't created, parent shows OutOfSync, or sync is stuck. Here are every cause and the exact fix.
ArgoCD Image Updater Not Syncing — Fix Guide
ArgoCD Image Updater detects a new image tag but doesn't update the Application. Here's how to diagnose and fix annotation errors, registry auth issues, write-back problems, and sync failures.