1. Introduction

A PersistentVolumeClaim stuck in Pending means Kubernetes cannot bind it to a PersistentVolume. Any pod that references this PVC will also be stuck in Pending, waiting for storage that never becomes available. This is a blocking issue for stateful workloads — databases, message queues, and any application that needs persistent storage can't start until the PVC is bound.

PVC Pending is almost always one of: no matching PV exists, the StorageClass doesn't have a working provisioner, or access mode and storage class constraints prevent binding. Each has a distinct fix.

2. What PVC Pending Means

When a PVC is created, the Kubernetes control plane tries to find a PV that satisfies the claim's requirements: sufficient storage, matching access mode, matching StorageClass, and matching label selectors. If dynamic provisioning is configured, the provisioner creates a new PV automatically. If no PV matches and no provisioner runs, the PVC stays Pending.

3. Common Causes

4. Step-by-Step Diagnosis and Fix

Step 1: Read the PVC events

# Check PVC status and events
kubectl describe pvc <pvc-name> -n <namespace>

# Common messages:
# "no persistent volumes available for this claim and no storage class is set"
# "storageclass.storage.k8s.io "fast-ssd" not found"
# "waiting for a volume to be created, either by external provisioner "
# "waiting for first consumer to be created before binding"  (WaitForFirstConsumer = normal)

# List all PVCs in the namespace
kubectl get pvc -n <namespace>

Step 2: Check if the StorageClass exists

# List available StorageClasses
kubectl get storageclass

# Check if there's a default StorageClass (marked with annotation)
kubectl get storageclass -o jsonpath='{range .items[*]}{.metadata.name}{"	"}{.metadata.annotations.storageclass\.kubernetes\.io/is-default-class}{"
"}{end}'

# Describe the StorageClass used by the PVC
kubectl describe storageclass <storageclass-name>
# Look at: Provisioner, ReclaimPolicy, VolumeBindingMode

Step 3: Check the provisioner is running

"># For AWS EBS CSI driver:
kubectl get pods -n kube-system -l app=ebs-csi-controller
kubectl logs -n kube-system -l app=ebs-csi-controller -c ebs-plugin --tail=50

# For GCE PD CSI driver:
kubectl get pods -n kube-system -l app=gcp-compute-persistent-disk-csi-driver

# For NFS provisioner:
kubectl get pods -n <provisioner-namespace>

# If the provisioner is crashing, check its logs for IAM/auth errors
kubectl logs -n kube-system <csi-controller-pod> --tail=100

Step 4: Fix — Create a matching PV manually (static provisioning)

apiVersion: v1
kind: PersistentVolume
metadata:
  name: my-pv
spec:
  capacity:
    storage: 10Gi
  accessModes:
    - ReadWriteOnce
  persistentVolumeReclaimPolicy: Retain
  storageClassName: manual
  hostPath:
    path: "/mnt/data"   # for testing; use proper backend in production
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: my-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 10Gi
  storageClassName: manual

Step 5: Fix — StorageClass with working provisioner

# For AWS EKS — ensure the EBS CSI driver is installed
kubectl get addon -n kube-system | grep ebs
# Install if missing:
eksctl create addon --name aws-ebs-csi-driver --cluster <cluster-name>   --service-account-role-arn arn:aws:iam::<account>:role/AmazonEKS_EBS_CSI_DriverRole

# Use the correct StorageClass for AWS:
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: gp3
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
parameters:
  type: gp3
  encrypted: "true"

Step 6: Fix — Access mode issues

# Check what access modes the StorageClass supports
kubectl describe storageclass <name>

# EBS/block storage supports: ReadWriteOnce only
# NFS/EFS supports: ReadWriteMany, ReadOnlyMany, ReadWriteOnce
# If you need ReadWriteMany, use NFS/EFS/CephFS/Azure Files

# Fix access mode in PVC:
spec:
  accessModes:
    - ReadWriteOnce  # change from ReadWriteMany if block storage

5. Verification Steps

# PVC should show Bound
kubectl get pvc -n <namespace>
# NAME      STATUS   VOLUME         CAPACITY   ACCESS MODES   STORAGECLASS
# my-pvc    Bound    pvc-abc123     10Gi       RWO            gp3

# Pods referencing the PVC should start
kubectl get pods -n <namespace> -l app=<your-app>

6. Common Mistakes

7. Prevention Tips

8. FAQ

The PVC was Bound and then went back to Pending. Is that possible?

Rare but possible. If the PV it was bound to was manually deleted, the PVC can return to Pending. Also, if the PVC's bound PV has a reclaimPolicy: Delete and the PV was released, it may be deleted — but the PVC will stay in a Lost state, not Pending. Check kubectl describe pvc for the current binding state and events.

How do I pre-provision PVs to avoid dynamic provisioning delays?

Create PVs statically with matching storageClassName, capacity, and accessModes, and leave their claimRef empty (the PVC will bind to the first matching available PV). For production, use dynamic provisioning with WaitForFirstConsumer — it's more flexible and avoids AZ mismatches that static pre-provisioning can introduce.

9. Summary

PVC event messageCauseFix
storageclass not foundStorageClass doesn't existCreate StorageClass or fix name typo in PVC
no volumes availableNo matching PV, no provisionerInstall CSI driver; create PV manually
waiting for first consumerWaitForFirstConsumer modeNormal — PVC binds when pod is scheduled
provisioner not foundCSI controller not runningDeploy CSI driver DaemonSet and controller
access mode not supportedWrong access mode for backendUse RWO for block; use NFS/EFS for RWX

Explore More in This Category

Explore more in this category: Kubernetes guides. Browse all DevOps Compass articles or jump to: Kubernetes, AWS, CI/CD, Containers, Monitoring, Networking.