Terraform Apply Hangs Forever: Fix in 5 Minutes
terraform apply stuck with no output, no progress, no error? Here is exactly how to diagnose provider API rate limits, state lock deadlocks, dependent resource waits, and network issues causing Terraform to hang indefinitely.
A hanging terraform apply is worse than a failing one — no error message means no obvious starting point. Here is how to find out what it's actually waiting on.
Step 1: Get Verbose Output to See What's Actually Happening
# Ctrl+C the hung apply first, then re-run with debug logging
TF_LOG=DEBUG terraform apply 2>&1 | tee terraform-debug.log
# While it's hanging, in another terminal, check the last few lines
tail -f terraform-debug.logThe last log lines before it goes silent tell you exactly which resource/API call it's stuck on — this is the single most useful diagnostic step and most people skip it.
Cause 1: Waiting on a Resource With a Long Create/Update Timeout
# In the debug log, you'll see something like:
# [DEBUG] Waiting for state to become: [available]
# aws_rds_cluster.main: Still creating... [10m0s elapsed]
This isn't actually hung — RDS clusters, EKS clusters, and some managed services genuinely take 10-20+ minutes to provision, and Terraform waits for the resource to report "ready" by design.
# Check the resource's actual status directly, outside Terraform
aws rds describe-db-clusters --db-cluster-identifier mycluster --query 'DBClusters[0].Status'Fix — if it's genuinely still provisioning, just wait. If AWS reports it as failed or stuck while Terraform is still "creating," the underlying resource has a real problem Terraform is just waiting on:
aws rds describe-events --source-identifier mycluster --source-type db-clusterCause 2: Rate Limited by the Provider API, Retrying Silently
# TF_LOG=DEBUG shows repeated silent retries:
# [DEBUG] [aws-sdk-go] DEBUG: Retrying Request
# Response body: <Error><Code>Throttling</Code>
Terraform's default retry behavior for throttled API calls can silently retry with exponential backoff for a long time without printing anything to normal output — it looks hung but is actually working through rate limits.
Fix — reduce parallelism so you generate fewer concurrent API calls:
terraform apply -parallelism=5 # Default is 10, lower it for accounts hitting rate limits# Or configure retry behavior explicitly in the provider block
provider "aws" {
max_retries = 25
}Cause 3: State Lock Held by a Stuck Previous Run
terraform apply
# Sits with no output at all, not even "Acquiring state lock..."If you don't even see the lock acquisition message, check if a previous run's lock is actually the block — some backends fail this silently rather than erroring immediately.
# For S3 + DynamoDB backend, check the lock table directly
aws dynamodb scan --table-name terraform-locks --query 'Items[*].LockID'Fix — if the lock is stale (owning process is genuinely dead, not just slow):
terraform force-unlock LOCK_IDOnly force-unlock after confirming the process that created the lock is actually dead — check with whoever might be running a concurrent apply first. See our Terraform state lock error fix for the full diagnostic flow.
Cause 4: Network Path to the Provider API Is Broken, No Timeout Set
# If TF_LOG=DEBUG shows nothing at all after "Acquiring state lock" —
# not even a request being made — check basic connectivity
curl -v https://ec2.us-east-1.amazonaws.com
# On a VPN, corporate proxy, or air-gapped runner, this can hang
# indefinitely with no built-in Terraform timeout for the initial connectionFix — verify network path and set explicit timeouts where the provider supports it:
# Check if a proxy is required and set it
export HTTPS_PROXY=http://proxy.internal:8080
terraform apply# Some providers support explicit timeouts per-resource
resource "aws_db_instance" "main" {
# ...
timeouts {
create = "20m" # Explicit ceiling instead of an indefinite wait
}
}Cause 5: A Data Source Depends on a Resource That Will Never Become Available
# If a data source references something that's misconfigured to never
# satisfy its own dependency, Terraform can appear stuck evaluating the graph
data "aws_lb_target_group" "existing" {
name = aws_lb_target_group.new.name # circular-ish dependency risk
}terraform graph | dot -Tsvg > graph.svg # Visualize the dependency graph to spot cycles or bad orderingFix — break the implicit dependency, reference outputs directly instead of re-querying:
# Instead of a data source re-lookup, reference the resource's own output
output "target_group_arn" {
value = aws_lb_target_group.new.arn
}Diagnostic Checklist
TF_LOG=DEBUG terraform apply 2>&1 | tail -50 # what was it doing last?
curl -v https://<provider-api-endpoint> # basic connectivity check
aws dynamodb scan --table-name terraform-locks # stale lock check (if using S3+DynamoDB backend)
terraform apply -parallelism=5 # reduce concurrent API loadMore Terraform troubleshooting? Read our Terraform state lock error fix and Terraform provider version conflict 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
Terraform Accidentally Destroyed Resources — How to Recover
You ran terraform apply and it deleted something it shouldn't have. Here's how to recover from accidental Terraform destroys before they become a disaster.
Terraform Backend S3 Init Failed — Every Cause and Fix (2026)
terraform init fails with S3 backend errors — access denied, bucket does not exist, state lock issues, wrong region. Here's every cause and the exact fix for each one.
Terraform Destroy Stuck on Dependency Violation: Fix in 5 Minutes
terraform destroy failing with 'DependencyViolation' or hanging on a resource that refuses to delete? Here is exactly how to diagnose orphaned dependencies, out-of-band changes, and deletion protection blocking a clean destroy.