Skip to main content

Fix Terraform Error: lifecycle prevent_destroy Blocks Destroy

Key Takeaway

Fix terraform prevent_destroy errors blocking resource deletion. Temporarily disable, use state rm to decouple, and understand when to use prevent_destroy for databases and S3 buckets.

Table of Contents

Quick Answer

# Temporarily set to false
lifecycle {
  prevent_destroy = false  # Was true
}
terraform apply   # Applies the lifecycle change
terraform destroy -target=aws_db_instance.main

Then re-enable prevent_destroy = true.

The Error

Error: Instance cannot be destroyed

  on rds.tf line 5:
   5: resource "aws_db_instance" "main" {

Resource aws_db_instance.main has lifecycle.prevent_destroy set, but the
plan calls for this resource to be destroyed. To avoid this error and
continue with the plan, either disable lifecycle.prevent_destroy or
reduce the scope of the change.

What Causes This

prevent_destroy = true in the lifecycle block intentionally blocks any operation that would destroy the resource. This triggers when:

  1. Running terraform destroy — directly deleting protected resources
  2. Changing a force-replacement attribute — e.g., changing RDS engine forces replacement (destroy + create)
  3. Removing the resource from config — deleting the resource block from .tf files
  4. Renaming the resourceaws_instance.webaws_instance.app without moved block

Solution 1: Temporarily Disable

resource "aws_db_instance" "main" {
  # ...

  lifecycle {
    prevent_destroy = false  # Temporarily disabled
  }
}
terraform apply            # Apply the lifecycle change
terraform destroy -target=aws_db_instance.main  # Now works

Remember to re-enable prevent_destroy = true for other environments!

Solution 2: Remove from State (Keep the Resource)

If you want to stop managing the resource without destroying it:

# Removes from Terraform state — the actual resource stays in AWS
terraform state rm aws_db_instance.main

Then remove the resource block from your .tf files. The database continues running, just no longer managed by Terraform.

Solution 3: Use moved Block for Renames

# This causes destroy + create (blocked by prevent_destroy)
# resource "aws_instance" "app" { ... }  # renamed from "web"

# Instead, use moved block (no destroy):
moved {
  from = aws_instance.web
  to   = aws_instance.app
}

resource "aws_instance" "app" {
  # ...
  lifecycle {
    prevent_destroy = true
  }
}

Solution 4: Reduce Scope of Change

If a force-replacement attribute triggers the error:

# ❌ This forces replacement (destroy + create) → blocked
resource "aws_db_instance" "main" {
  engine = "mysql"      # Was "postgres"  can't change in-place
  lifecycle { prevent_destroy = true }
}

# ✅ Create new instance with different name, migrate data, then remove old
resource "aws_db_instance" "main_v2" {
  engine = "mysql"
}

When to Use prevent_destroy

Use it on resources where accidental deletion is catastrophic:

# Databases — data loss
resource "aws_db_instance" "production" {
  lifecycle { prevent_destroy = true }
}

resource "aws_rds_cluster" "production" {
  lifecycle { prevent_destroy = true }
}

# S3 buckets with important data
resource "aws_s3_bucket" "backups" {
  lifecycle { prevent_destroy = true }
}

# DNS zones
resource "aws_route53_zone" "primary" {
  lifecycle { prevent_destroy = true }
}

# KMS keys (can't be recreated with same ID)
resource "aws_kms_key" "main" {
  lifecycle { prevent_destroy = true }
}

Don’t use it on:

  • EC2 instances (replaceable)
  • Security groups (no data loss)
  • IAM roles (recreatable)

Combining with AWS Protection

resource "aws_db_instance" "main" {
  deletion_protection = true   # AWS-level protection

  lifecycle {
    prevent_destroy = true     # Terraform-level protection
  }
}

Double protection: Terraform won’t plan the destroy, AND AWS won’t execute it even if Terraform tried.

Hands-On Courses

Conclusion

prevent_destroy = true is working as intended — it’s protecting your resource. Temporarily set it to false to destroy, use terraform state rm to decouple without destroying, or use moved blocks for renames. Apply it to databases, S3 buckets, and DNS zones — anything where data loss would be catastrophic.

🚀

Level Up Your Terraform Skills

Hands-on courses, books, and resources from Luca Berton

Luca Berton
Written by

Luca Berton

DevOps Engineer, AWS Partner, Terraform expert, and author. Creator of Ansible Pilot, Terraform Pilot, and CopyPasteLearn.