PVC stuck in Pending: Fix Persistent Volume Claim Not Bound
Your Persistent Volume Claim stays Pending forever. We'll walk through three fixes: start with the 30-second check, then move deeper.
Before You Start
You created a PersistentVolumeClaim (PVC) in Kubernetes. It stays stuck in Pending. Pods that need this volume won't start. This guide fixes that. You'll need kubectl access to your cluster. I'll assume you're using a recent version of Kubernetes (1.20 or later).
Here's how we'll work: start with a 30-second check (the simplest fix), then a 5-minute fix, then a deeper 15-minute fix. Stop when your PVC shows Bound.
Fix 1: The 30-Second Check – StorageClass Exists?
Most times a PVC gets stuck because the StorageClass doesn't exist on the cluster. Your PVC asks for a specific StorageClass, but it's not there. The cluster can't provision a volume.
Step 1: Check your PVC
Run this to see the PVC details:
kubectl get pvc my-pvc -o yaml
Look for the storageClassName field. If it's empty, Kubernetes uses the default StorageClass. If it's set to something like fast-ssd, that class must exist.
Step 2: List StorageClasses
Run:
kubectl get storageclass
If the list is empty, or if your specific class is missing, that's your problem. Kubernetes can't create a volume without a StorageClass.
Step 3: Create or choose the right class
If the class is missing, you have two options:
- Create a new StorageClass that matches what your PVC asks for. For example, on a cloud cluster you might use the default provisioner.
- Change your PVC to use an existing class. Just edit the
storageClassNamein your PVC YAML and reapply.
Expected outcome: After you fix the StorageClass, recheck the PVC. Run kubectl get pvc. If it shows Bound, you're done. If it's still Pending, move to the next fix.
Fix 2: The 5-Minute Fix – Static PV Exists?
If you're not using dynamic provisioning (no StorageClass, or a class with provisioner: kubernetes.io/no-provisioner), then you need a PersistentVolume (PV) that already exists. Your PVC waits for a PV that matches its size and access modes.
Step 1: Check all PVs
Run:
kubectl get pv
Look at the STATUS column. If there's a PV with Available status, it might work. If the list is empty, you need to create a PV.
Step 2: Match the PVC's requirements
Your PVC has:
- Requested storage size (e.g., 10Gi)
- Access mode (e.g., ReadWriteOnce)
- Optional: storage class (if set, the PV must also have that class or be labeled with storageClassName: "")
Find an Available PV that meets all these. If none exists, create one. Quick example for a local path PV:
apiVersion: v1
kind: PersistentVolume
metadata:
name: local-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
hostPath:
path: /mnt/data
Apply it with kubectl apply -f pv.yaml. Then recheck the PVC.
Expected outcome: Within a minute, the PVC should bind to the PV. If it's still Pending, move to the next fix.
Fix 3: The 15+ Minute Fix – Provisioner Logs
If you have a StorageClass that should work (like an AWS EBS provisioner), but the PVC stays Pending, something is wrong with the provisioner itself. This happens more often than you'd think. Misconfigured cloud credentials, missing CSI driver, or node issues can all cause this.
Step 1: Describe the PVC for error messages
Run:
kubectl describe pvc my-pvc
Scroll to the bottom where it says Events. Look for lines like Failed to provision volume with StorageClass or volume limit reached. The error message tells you what's wrong. Common ones:
- "AccessDenied" – Cloud provider credentials are missing or wrong.
- "InvalidParameterValue" – The requested volume size or type isn't supported in your region.
- "timeout waiting for volume to be created" – The cloud API isn't responding.
Step 2: Check the provisioner pod logs
The provisioner runs as a pod (often in kube-system). For example, on AWS with EBS CSI driver:
kubectl get pods -n kube-system | grep ebs
Then get logs:
kubectl logs -n kube-system ebs-csi-controller-xxxx --tail=50
Look for lines with error or fail. That's where the real problem hides. If you see NoCredentialProviders, you need to fix IAM roles. If you see invalid zone, your node's zone might not support the volume type.
Step 3: Check node readiness and topology
Sometimes a PVC can't bind because the PV is in a different zone than the pod. For static PVs, you need to add nodeAffinity to the PV so Kubernetes knows where to find it. Example:
spec:
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: topology.kubernetes.io/zone
operator: In
values:
- us-east-1a
Without that, the PVC will stay Pending.
Still Stuck?
If all three fixes didn't work, you're dealing with a rare edge case. Check these:
- Quota limits – Your cloud account might have a volume limit per region. Check your cloud provider console.
- CSI driver version – Some older drivers don't support certain features. Update your driver.
- Cluster autoscaler interference – If your nodes are scaled down, the PVC can't bind until a node exists in the right zone.
For the quickest path, delete the PVC and recreate it with a simple kubectl delete pvc my-pvc && kubectl apply -f pvc.yaml. Sometimes the binding process gets stuck in a weird state. That clears it.
Was this solution helpful?