Skip to main content
RunBook Academy

KubernetesLIII · Storage Failure ModesStorage failure modes

PVC Pending — the diagnostic ladder for a stuck volume claim

Advanced⏱ ~16 minkubectl

What you'll learn

  • Diagnose a Pending PVC using events and logs
  • Identify the four common causes: StorageClass, provisioner, capacity, topology
  • Apply the production fixes for each cause
  • Monitor for Pending PVCs as a SLO

Prerequisites

Verified against Kubernetes 1.34.x · kubeadm 1.34.x · kubectl 1.34.x · etcd 3.6.x · CoreDNS 1.11.x · containerd 1.7.x / 2.x · 2026-08-16

Not yet marked complete on this device.

A PVC in Pending state is the most common storage incident. The cause is one of four categories: the StorageClass, the provisioner, the capacity, or the topology. This lesson walks the diagnostic ladder and the production fixes.

The four common causes

CauseSymptomDiagnostic
StorageClassNo matching PV, no provisionerkubectl describe pvc events
ProvisionerProvisioner is down or throttledCSI controller logs
CapacityBackend quota exceededBackend metrics, CSI controller logs
TopologyNo matching AZ / regionNode topology labels, StorageClass allowedTopologies
flowchart TD
    A[PVC Pending] --> B{kubectl describe pvc}
    B --> C{StorageClass issue?}
    B --> D{Provisioner issue?}
    B --> E{Capacity issue?}
    B --> F{Topology issue?}
    C -->|yes| G[Fix StorageClass]
    D -->|yes| H[Fix provisioner]
    E -->|yes| I[Increase quota or reduce request]
    F -->|yes| J[Fix topology constraints]

Cause 1: StorageClass

The most common cause: the PVC requests a StorageClass that does not exist, has no provisioner, or has a provisioner that is not running.

# Substitute your own value before running:
PVC=data-postgres-0

kubectl describe pvc "$PVC"
# Events:
#   Warning  ProvisioningFailed  ... no persistent volumes available
#                                for this claim and no storage class is set
#   Warning  ProvisioningFailed  ... storageclass "nonexistent" not found

The fix:

  • Create the StorageClass if it does not exist.
  • Verify the provisioner name matches a running CSI driver.
  • Verify the StorageClass parameters are valid.

Cause 2: Provisioner

The provisioner (CSI driver) is down, throttled, or has configuration errors.

# Substitute your own value before running - the `app` label the CSI
# driver's controller Deployment carries (e.g. ebs-csi-controller):
CSI_DRIVER=ebs-csi-controller

# Check the controller plugin
kubectl -n kube-system get pods -l "app=$CSI_DRIVER,role=controller"

# Check the controller plugin logs
kubectl -n kube-system logs -l "app=$CSI_DRIVER,role=controller" --tail=50

Common provisioner issues:

  • Pod down: the controller plugin Deployment is missing replicas. The fix: investigate why.
  • API throttling: the backend API is throttled (AWS, GCP, Azure). The fix: reduce the PVC submission rate or request a quota increase.
  • IAM permissions: the CSI driver does not have permission to call the backend. The fix: update IAM permissions.
  • Parameter validation: the StorageClass parameters are invalid. The fix: correct the parameters.

Cause 3: Capacity

The backend cannot fulfill the PVC’s capacity request:

  • The PVC requests more than the backend allows (e.g., 100 TB on EBS).
  • The cluster has reached its storage quota (e.g., AWS account limit).
  • The StorageClass’s parameters exceed the backend’s limits (e.g., 100000 IOPS on gp3).
# Substitute your own value before running:
PVC=data-postgres-0

kubectl describe pvc "$PVC"
# Events:
#   Warning  ProvisioningFailed  ... exceeded quota: storage-gigabytes

The fix:

  • Reduce the PVC’s capacity request.
  • Reduce the StorageClass’s parameters (e.g., lower IOPS).
  • Request a quota increase from the cloud provider.

Cause 4: Topology

The PVC cannot be created in any zone that matches the Pod’s topology:

  • The StorageClass’s allowedTopologies does not include the cluster’s zones.
  • The StorageClass has Immediate binding on a multi-AZ cluster, and the PV is created in a different AZ than the Pod.
# Substitute your own value before running:
PVC=data-postgres-0

kubectl describe pvc "$PVC"
# Events:
#   Warning  ProvisioningFailed  ... no topology constraints found

The fix:

  • Set volumeBindingMode: WaitForFirstConsumer so the PV is created in the Pod’s AZ.
  • Set allowedTopologies to include the cluster’s AZs.

The diagnostic ladder

flowchart TD
    A[PVC Pending] --> B[kubectl describe pvc]
    B --> C{Event message?}
    C -->|StorageClass not found| D[Create StorageClass]
    C -->|Provisioner error| E[kubectl logs controller plugin]
    C -->|Quota exceeded| F[Backend quota]
    C -->|Topology| G[Verify allowedTopologies]
    C -->|No events| H[Bare PVC: default StorageClass missing]
    E -->|throttling| I[Reduce rate or request quota]
    E -->|IAM| J[Fix permissions]
    E -->|parameters| K[Fix parameters]

The monitoring

A PVC in Pending state blocks the Pod that mounts it. The monitoring:

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: storage-pending
spec:
  groups:
  - name: storage
    rules:
    - alert: PVCPendingTooLong
      expr: |
        kube_persistentvolumeclaim_status_phase{phase="Pending"} == 1
      for: 5m
      labels:
        severity: warning
      annotations:
        summary: "PVC {{ $labels.persistentvolumeclaim }} pending in ns {{ $labels.namespace }} for 5+ minutes"

The alert catches PVCs that are Pending for more than 5 minutes. The diagnostic then walks the ladder.

The production fix

For each cause:

CauseProduction fix
StorageClass missingCreate the StorageClass; verify the provisioner
Provisioner downInvestigate the Deployment; restart if needed
Provisioner throttledReduce PVC rate; request quota
Provisioner IAMFix IAM permissions; restart
Provisioner parametersValidate parameters; correct
Capacity too highReduce PVC request
Quota exceededRequest quota increase
Topology mismatchSet WaitForFirstConsumer; verify allowedTopologies

Quiz

Knowledge check · 4 questions

  1. Q1. A PVC is Pending for 10 minutes. The events show `no persistent volumes available for this claim and no storage class is set`. What is the most likely cause?

  2. Q2. A PVC in `Pending` state does not block the Pod that mounts it from being scheduled; the Pod waits for the PVC.

  3. Q3. Your team submits a new PVC for a PostgreSQL StatefulSet. The PVC is Pending for 15 minutes. Walk through the diagnostic ladder.

    PVC: storageClassName: db-ssd, 100 GB, ReadWriteOnce. Pending for 15 minutes. The cluster has a db-ssd StorageClass backed by the EBS CSI driver.

  4. Q4. Explain the four common causes of a Pending PVC and the diagnostic for each.

Passing score: 75%. Answers are checked in this browser.

Production discipline

  • Pending PVC is a SLO. A PVC in Pending blocks the Pod; the workload is unavailable.
  • The diagnostic ladder is events -> logs -> backend. Each layer reveals a different cause.
  • Monitor for Pending PVCs. Alert on Pending for 5+ minutes.
  • Validate StorageClasses with test PVCs. A regular validation catches misconfigurations before workloads deploy.
  • Document the fix in the runbook. The fix is per-cause; the runbook has the diagnostic for each.