TL;DR
Terraform gave up waiting for a resource to finish provisioning. Add a timeouts block to that resource and re-run terraform apply โ this resolves the problem in most cases.
resource "aws_eks_cluster" "main" {
name = "my-cluster"
role_arn = aws_iam_role.eks.arn
timeouts {
create = "30m"
delete = "20m"
}
}
What Triggers This Error
Under the hood, terraform apply polls each resource until it reports ready. Every resource type ships with a built-in deadline โ typically 10โ40 minutes depending on what it is. Spin up an aws_eks_cluster and you get 30 minutes; an aws_db_instance gets 40 minutes by default. Miss that window โ slow region, large instance, flaky API โ and Terraform bails:
Error: A resource could not be created during the last apply. The resource provisioning timed out.
Resources that hit this most often:
- EKS / GKE / AKS clusters
- RDS instances (especially Multi-AZ)
- ElastiCache clusters
- Large EC2 instances with user-data scripts
- VPN gateways and Transit Gateways
- Kubernetes resources via the
kubernetesprovider
One thing to keep in mind: the resource may already exist in the cloud. Terraform just ran out of patience waiting for it. Check your cloud console before assuming nothing was created.
Step 1 โ Check What Was Actually Created
Before touching anything in Terraform, verify whether the resource exists in the cloud โ it may simply be running slow.
# AWS example โ check if the RDS instance exists
aws rds describe-db-instances --db-instance-identifier my-db --query 'DBInstances[*].DBInstanceStatus'
# Or check EKS cluster status
aws eks describe-cluster --name my-cluster --query 'cluster.status'
If the status shows creating or available, the resource is fine โ Terraform just ran out of patience. Sync state first, then apply:
terraform refresh
terraform apply
Step 2 โ Increase the Timeout
Most Terraform resource types accept a timeouts block. Slot it inside the resource definition. The available keys โ create, update, delete โ vary by resource type, so check the docs if unsure.
RDS Example
resource "aws_db_instance" "postgres" {
identifier = "my-db"
engine = "postgres"
instance_class = "db.r5.2xlarge"
multi_az = true
allocated_storage = 100
timeouts {
create = "60m"
update = "80m"
delete = "40m"
}
}
EKS Cluster Example
resource "aws_eks_cluster" "main" {
name = "production"
role_arn = aws_iam_role.eks.arn
vpc_config {
subnet_ids = var.subnet_ids
}
timeouts {
create = "30m"
delete = "15m"
}
}
Google Cloud SQL Example
resource "google_sql_database_instance" "main" {
name = "my-instance"
database_version = "POSTGRES_14"
region = "us-central1"
timeouts {
create = "30m"
update = "30m"
delete = "30m"
}
settings {
tier = "db-custom-4-16384"
}
}
Save the file and apply:
terraform apply
Step 3 โ Handle a Stuck State
Sometimes Terraform leaves behind a half-written state entry for a resource that never finished provisioning. Clean that up before trying again.
Check Current State
terraform state list
terraform state show aws_db_instance.postgres
Remove Orphaned State (if the resource doesn't exist in the cloud)
# Remove the broken resource from state so Terraform will try creating it again
terraform state rm aws_db_instance.postgres
Import an Existing Resource (if it was created but Terraform lost track)
# Import existing RDS instance into state
terraform import aws_db_instance.postgres my-db
# Then verify
terraform plan
Step 4 โ Investigate Slow Provisioning
Raising the timeout ceiling treats the symptom, not the cause. If an EKS cluster that used to launch in 15 minutes now takes 45, something changed โ and it's worth finding out what.
EC2 User-Data Scripts
A startup script that runs for 10+ minutes will keep the instance stuck in pending the whole time. Pull the console output to see where it's hanging:
aws ec2 get-console-output --instance-id i-0abc123 --output text
Move heavy initialization out of user-data โ use a configuration management tool like Ansible or Chef, or bake a custom AMI with the software already installed.
Large EBS Volumes
A 2TB gp2 volume can take 20+ minutes to initialize from scratch. Switch to gp3 instead โ it delivers 3,000 IOPS baseline regardless of size, and initialization completes significantly faster. For critical workloads, enable fast snapshot restore on the source snapshot.
resource "aws_ebs_volume" "data" {
availability_zone = "us-east-1a"
size = 2000
type = "gp3" # faster than gp2 for large volumes
throughput = 500
}
Kubernetes Resources
The kubernetes and helm providers wait for deployments to reach a ready state. If the pod keeps crashing, no amount of extra timeout will help โ Terraform will just wait longer before failing. Check the pod directly:
kubectl get pods -n my-namespace
kubectl describe pod my-app-xxx -n my-namespace
kubectl logs my-app-xxx -n my-namespace
Fix the underlying pod issue first. The Terraform timeout is irrelevant until the container itself is healthy.
Step 5 โ Verify the Fix
Once terraform apply completes, do a quick sanity check from both sides:
# Confirm Terraform sees it as created
terraform state show aws_db_instance.postgres
# Check no pending changes remain
terraform plan
# Expected output:
# No changes. Your infrastructure matches the configuration.
Then confirm from the AWS side:
aws rds describe-db-instances \
--db-instance-identifier my-db \
--query 'DBInstances[*].{ID:DBInstanceIdentifier,Status:DBInstanceStatus}'
Quick Reference โ Default Timeouts by Resource
aws_db_instanceโ create: 40m, update: 80m, delete: 60maws_eks_clusterโ create: 30m, delete: 15maws_elasticache_clusterโ create: 40m, delete: 40maws_instanceโ create: 10m, update: 10m, delete: 20mgoogle_container_clusterโ create: 40m, update: 60m, delete: 40mazurerm_kubernetes_clusterโ create: 90m, update: 90m, delete: 90m
Not every resource exposes all three keys โ check the Terraform Registry docs before assuming update or delete are available for your resource.
Further Reading
- Terraform docs: Operation Timeouts
- AWS RDS resource docs on Terraform Registry
- Run
TF_LOG=DEBUG terraform applyto trace exactly where time is being spent during provisioning

