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.
It happens to everyone. A terraform apply that was supposed to update a tag deleted the RDS instance. Or refactoring moved a resource and Terraform decided to destroy-and-recreate instead of update.
Here's how to recover — fast.
First: Stop the Bleeding
If the destroy is still in progress:
# Ctrl+C immediately
# Terraform will finish the current operation but stop queuing new ones
# Don't run anything else until you understand what happenedIf it already completed, check what was destroyed:
# Check state for what's gone
terraform state list
# Check the plan that was applied
# (if you used -out flag, the plan file shows what was destroyed)Case 1: RDS / Database Deleted
If you have automated backups enabled (you should):
# AWS Console → RDS → Snapshots → Automated backups
# Or via CLI
aws rds describe-db-snapshots \
--query 'DBSnapshots[?DBInstanceIdentifier==`your-db`]' \
--output table
# Restore from snapshot
aws rds restore-db-instance-from-db-snapshot \
--db-instance-identifier your-db-restored \
--db-snapshot-identifier rds:your-db-2026-05-29-00-01Then import into Terraform state:
terraform import aws_db_instance.main your-db-restoredCase 2: EC2 / EBS Volume Deleted
EC2 instances can't be recovered once terminated (unless you have an AMI). But EBS volumes can if they weren't deleted with the instance:
# Check if volume still exists (might be in "available" state)
aws ec2 describe-volumes \
--filters "Name=status,Values=available" \
--query 'Volumes[*].[VolumeId,Size,AvailabilityZone]'
# If found, create new instance and attach
aws ec2 attach-volume \
--volume-id vol-xxxxxxxx \
--instance-id i-xxxxxxxx \
--device /dev/sdfCase 3: S3 Bucket Deleted
If versioning was enabled:
# Versioning protects objects even if bucket is deleted? No.
# Bucket deletion removes everything.
# Check if bucket still shows in AWS (might be soft-deleted briefly)
aws s3 ls | grep your-bucket-name
# If using S3 replication, check destination bucket
aws s3 ls s3://your-replica-bucket/Prevention: Enable S3 Object Lock or replicate to another region.
Case 4: Wrong Resource Destroyed (Resource Still Exists in AWS, Just Missing from State)
Most common scenario when refactoring. The resource exists in AWS but Terraform state doesn't know about it.
# Re-import the existing resource into state
terraform import aws_instance.web i-1234567890abcdef0
terraform import aws_security_group.main sg-12345678
terraform import aws_s3_bucket.data my-bucket-name
# Verify
terraform plan
# Should show "No changes" if import was correctCase 5: Terraform Destroy-and-Recreate During Rename
When you rename a resource in Terraform, it destroys old and creates new:
# Before
resource "aws_instance" "web_server" { ... }
# After (rename) — Terraform treats this as destroy old + create new!
resource "aws_instance" "application_server" { ... }Fix with moved block (Terraform 1.1+):
moved {
from = aws_instance.web_server
to = aws_instance.application_server
}This tells Terraform it's the same resource, just renamed. No destroy.
How to Prevent This in the Future
1. Lifecycle protect on critical resources
resource "aws_db_instance" "production" {
# ...
lifecycle {
prevent_destroy = true # terraform destroy will error out
}
}2. Always run plan before apply
# Save plan to file
terraform plan -out=tfplan
# Review it (look for any "-" destroy lines)
terraform show tfplan | grep -E "^ # |will be destroyed|must be replaced"
# Only apply if plan looks right
terraform apply tfplan3. Use -target for surgical applies
# Only apply changes to one resource
terraform apply -target=aws_instance.web4. Enable state locking + versioning
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
encrypt = true
dynamodb_table = "terraform-locks" # state locking
}
}Enable versioning on the S3 bucket — you can roll back to a previous state:
# List state versions
aws s3api list-object-versions --bucket my-terraform-state --prefix prod/terraform.tfstate
# Restore previous version
aws s3api get-object \
--bucket my-terraform-state \
--key prod/terraform.tfstate \
--version-id <version-id> \
terraform.tfstate.backup5. Use Atlantis or Terraform Cloud for PR-based applies
Never apply from a local machine in production. All applies go through PR review with a plan posted as a comment.
Quick Recovery Checklist
- Check AWS Console for the resource (might still exist)
- Check automated backups / snapshots
- Check S3 state bucket for previous state versions
- Re-import if resource exists in AWS
- Restore from backup if truly deleted
- Add
prevent_destroyto critical resources after recovery
Accidental destroys are painful the first time. Set up prevent_destroy on production databases, S3 buckets, and VPCs today — before it happens again.
Practice Terraform in safe sandboxes — KodeKloud Terraform labs let you break things without consequences.
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 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 Module Version Conflict — Fix Guide (2026)
Terraform failing with version constraint conflicts between modules? Here's how to diagnose which module is causing the conflict and resolve it without breaking everything.
Terraform Plan Succeeds But Apply Fails: How to Fix State Drift and Provider Errors
Your terraform plan looks clean but apply blows up? Here's how to fix provider conflicts, state drift, and dependency errors step by step.