By Fatskills Exam Guides Team — the exam nerds behind 28,500+ quizzes and 2.1M practice questions across 500+ global exams.
Terraform state locking prevents multiple engineers (or CI/CD pipelines) from running terraform apply at the same time on the same state file. Without locking, you risk state corruption—imagine two teammates pushing changes simultaneously, overwriting each other’s work like two people editing the same Google Doc without seeing each other’s cursors.
terraform apply
Real-world scenario:You’re on a team of 5 cloud engineers. Alice runs terraform apply to update an EKS cluster. At the same time, Bob runs terraform apply to scale an RDS instance. Without state locking, Terraform merges their changes unpredictably—Bob’s RDS scaling might overwrite Alice’s EKS updates, or worse, the state file becomes corrupted, forcing you to manually reconcile resources (a nightmare).
What breaks if you ignore it?- State corruption → Manual fixes, downtime, and lost trust in IaC.- Race conditions → Inconsistent infrastructure (e.g., half-updated security groups).- CI/CD failures → Pipelines clash, causing flaky deployments.
Superpower it gives you:- Safe team collaboration → Multiple engineers can work on the same Terraform codebase without stepping on each other.- Reliable CI/CD → No more "works on my machine" because the pipeline failed due to a race condition.- Audit trail → DynamoDB logs who locked the state and when (useful for debugging).
terraform.tfstate The JSON file tracking your infrastructure’s current state. If two processes modify it simultaneously, it becomes corrupted. Production insight: Always store this in remote backend (S3, Azure Blob, GCS) with versioning enabled. Never commit it to Git.
terraform.tfstate
State Locking A mechanism that blocks concurrent terraform apply operations by acquiring an exclusive lock on the state file. Production insight: Without locking, you’re one terraform apply away from a 3 AM fire drill.
DynamoDB (AWS) A NoSQL database used to store lock metadata (who locked it, when, and why). Terraform checks this table before allowing a write operation. Production insight: Use on-demand capacity for cost efficiency—locking is infrequent but critical.
Lock ID A unique identifier (usually a UUID) stored in DynamoDB to represent the current lock. Terraform checks this before proceeding. Production insight: If a lock isn’t released (e.g., due to a crashed terraform apply), you must manually delete the DynamoDB item.
Backend Configuration The backend block in Terraform that defines where state is stored (S3) and where locks are managed (DynamoDB). Production insight: Misconfigure this, and your team will be locked out of state updates.
backend
force-unlock Command Terraform’s escape hatch to manually release a stuck lock (e.g., if a CI job crashes mid-apply). Production insight: Use this only as a last resort—it can cause state corruption if misused.
force-unlock
OSS (Open-Source) Alternatives For non-AWS environments, you can use:
pg
✅ AWS account with admin IAM permissions (or at least dynamodb:* and s3:*).✅ AWS CLI configured (aws configure).✅ Terraform installed (terraform --version).✅ A Terraform project (even a simple one, like an S3 bucket).
dynamodb:*
s3:*
aws configure
terraform --version
Terraform needs a DynamoDB table with a primary key named LockID (case-sensitive).
LockID
Run this AWS CLI command:
aws dynamodb create-table \ --table-name terraform_locks \ --attribute-definitions AttributeName=LockID,AttributeType=S \ --key-schema AttributeName=LockID,KeyType=HASH \ --billing-mode PAY_PER_REQUEST
Why PAY_PER_REQUEST? - No upfront capacity planning.- Costs pennies (DynamoDB charges per request, and locking is infrequent).
PAY_PER_REQUEST
Verify the table exists:
aws dynamodb describe-table --table-name terraform_locks
Expected output:
{ "Table": { "TableName": "terraform_locks", "KeySchema": [{ "AttributeName": "LockID", "KeyType": "HASH" }], "BillingModeSummary": { "BillingMode": "PAY_PER_REQUEST" } } }
Add this to your main.tf (or a dedicated backend.tf):
main.tf
backend.tf
terraform { backend "s3" { bucket = "your-unique-bucket-name" # Replace with your S3 bucket key = "terraform.tfstate" # Path to state file region = "us-east-1" # AWS region dynamodb_table = "terraform_locks" # DynamoDB table name encrypt = true # Enable encryption at rest } }
Key details: - bucket: Must exist before running terraform init.- key: Path to your state file (e.g., prod/terraform.tfstate for environments).- encrypt: Always true—state files often contain secrets.
bucket
terraform init
key
prod/terraform.tfstate
encrypt
true
Create the S3 bucket (if it doesn’t exist):
aws s3api create-bucket --bucket your-unique-bucket-name --region us-east-1 aws s3api put-bucket-versioning --bucket your-unique-bucket-name --versioning-configuration Status=Enabled
Why versioning? - If state gets corrupted, you can roll back to a previous version.
Run:
Initializing the backend...Successfully configured the backend "s3"! Terraform will automatically use this backend unless the backend configuration changes.
Verify the backend is configured:
terraform state list
If you see resources, it worked!
Open two terminal windows and run terraform apply in both simultaneously.
Terminal 1:
Output:
Acquiring state lock. This may take a few moments...
Terminal 2:
╷ │ Error: Error acquiring the state lock │ │ Error message: ConditionalCheckFailedException: The conditional request failed │ Lock Info: │ ID: 123e4567-e89b-12d3-a456-426614174000 │ Path: your-unique-bucket-name/terraform.tfstate │ Operation: OperationTypeApply │ Who: user@hostname │ Version: 1.5.7 │ Created: 2023-10-01 12:00:00 +0000 UTC │ Info: ╵
What just happened? - Terminal 1 acquired the lock.- Terminal 2 was blocked and got a clear error message.
Release the lock (in Terminal 1):Press Ctrl+C or let the apply finish. The lock will auto-release.
Ctrl+C
Simulate a stuck lock:1. Run terraform apply in Terminal 1.2. Kill the process (Ctrl+Z or kill -9).3. Try terraform apply in Terminal 2—it’ll fail with the same error.
Ctrl+Z
kill -9
Fix it:
terraform force-unlock 123e4567-e89b-12d3-a456-426614174000
Replace 123e4567... with the ID from the error message.
123e4567...
ID
⚠️ Warning: - Only use force-unlock if you’re 100% sure no other process is using the state.- If in doubt, check the DynamoDB table: bash aws dynamodb get-item --table-name terraform_locks --key '{"LockID": {"S": "your-unique-bucket-name/terraform.tfstate"}}'
bash aws dynamodb get-item --table-name terraform_locks --key '{"LockID": {"S": "your-unique-bucket-name/terraform.tfstate"}}'
dynamodb:GetItem
dynamodb:PutItem
dynamodb:DeleteItem
s3:GetObject
s3:PutObject
s3:ListBucket
aws:kms
PROVISIONED
STANDARD
GLACIER
DEEP_ARCHIVE
dev/terraform.tfstate
hcl terraform { backend "s3" { key = "prod/terraform.tfstate" # Environment-specific path } }
Environment=prod
Team=infra
create_before_destroy
ThrottledRequests
> 0
ConditionalCheckFailedException
dynamodb_table
NoSuchBucket
terraform force-unlock <ID>
❌ RDS (overkill for locking).
"What happens if two engineers run terraform apply simultaneously without locking?"
❌ "The second apply fails gracefully" (false without locking).
"How do you manually release a stuck Terraform lock?"
terraform unlock
❌ Delete the DynamoDB item manually (risky).
"What’s the minimum IAM permission needed for DynamoDB locking?"
prod
dev
Challenge:You’re working on a team where terraform apply keeps failing with:
Error: Error acquiring the state lock Lock Info: ID: abc123... Path: my-bucket/terraform.tfstate
The lock is stuck because a CI job crashed. Fix it without corrupting state.
Solution:
terraform force-unlock abc123...
Why it works: - force-unlock safely releases the lock by deleting the DynamoDB item only if no other process is using it.- Terraform validates the lock ID before deleting it.
aws dynamodb create-table --table-name terraform_locks --attribute-definitions AttributeName=LockID,AttributeType=S --key-schema AttributeName=LockID,KeyType=HASH --billing-mode PAY_PER_REQUEST
aws dynamodb get-item --table-name terraform_locks --key '{"LockID": {"S": "bucket/path"}}'
bucket/path
backend "s3"
encrypt=true
S3 versioning
Join 4M+ learners. Unlock unlimited quizzes, wrong-answer tracking, flashcards + reminders, study guides, and 1-on-1 challenges.