How to fix Error: Error loading state: AccessDenied in Terraform

TerraformINTERMEDIATEHIGHUpdated Dec 30, 2025· 99 views

Terraform cannot access the S3 backend state file due to insufficient AWS IAM permissions or misconfigured credentials. This prevents Terraform from reading or managing infrastructure state.

Quick fix

Fixes AccessDenied

aws sts get-caller-identity
  1. Verify your AWS credentials are configured
  2. Test S3 bucket access with AWS CLI
  3. Check IAM permissions on the S3 bucket
  4. Add KMS permissions if using encryption
terraform — error
aws sts get-caller-identity
Error: Error loading state: AccessDenied

What this error means

This error occurs when Terraform attempts to load your state file from an S3 backend but lacks the necessary AWS credentials or permissions. The AccessDenied error indicates that while Terraform successfully connected to AWS, the credentials being used do not have permission to read the S3 bucket or the state file within it. This is a critical error because Terraform cannot proceed without accessing the state file.

Typical symptoms

  • Terraform init fails with 'Error loading state: AccessDenied' message
  • terraform plan and terraform apply commands fail before any operations execute
  • Error occurs even though you can access the S3 bucket via AWS CLI with the same credentials
  • CI/CD pipelines fail during the terraform init step
  • The error mentions HTTP 403 or Access Denied status code

Common causes

  1. IAM user or role lacks s3:GetObject permission on the state file
  2. IAM user or role lacks s3:ListBucket permission on the S3 bucket
  3. Terraform is using AWS credentials from environment variables or a default profile that differ from expected credentials
  4. The configured AWS profile in the backend configuration is being ignored, and a different (unauthorized) profile is being used
  5. S3 bucket policy explicitly denies access to the IAM principal
  6. Missing KMS permissions if the S3 bucket uses encryption with a customer-managed key
  7. Cross-account access using role_arn without proper trust relationship setup
  8. Bucket object ACLs prevent access despite IAM permissions

How to fix "Error: Error loading state: AccessDenied"

1Verify your AWS credentials are configured

Check that your AWS credentials are properly set up. Terraform will look for credentials in this order:
1. Environment variables: AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY
2. AWS credentials file: ~/.aws/credentials
3. AWS config file: ~/.aws/config with a profile
4. IAM role (if running on EC2, ECS, or Lambda)

Run this command to verify your current AWS identity:

bash
aws sts get-caller-identity

This will show you which AWS account and IAM principal is being used.

2Test S3 bucket access with AWS CLI

Before troubleshooting Terraform, verify that you can access the S3 bucket using AWS CLI with the same credentials:

bash
# List the bucket contents
aws s3 ls s3://your-terraform-state-bucket/

# Try to read the state file directly
aws s3 cp s3://your-terraform-state-bucket/terraform.tfstate ./test-state.tfstate

If these commands fail with AccessDenied, the issue is with AWS permissions, not Terraform configuration.

3Check IAM permissions on the S3 bucket

Verify that your IAM user or role has the required S3 permissions. The IAM policy must include:

json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:ListBucket",
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject"
      ],
      "Resource": [
        "arn:aws:s3:::your-terraform-state-bucket",
        "arn:aws:s3:::your-terraform-state-bucket/*"
      ]
    }
  ]
}

The most commonly missing permission is s3:ListBucket, which is required at the bucket level, not the object level.

4Add KMS permissions if using encryption

If your S3 bucket uses encryption with a customer-managed KMS key, add these permissions to your IAM policy:

json
{
  "Effect": "Allow",
  "Action": [
    "kms:Decrypt",
    "kms:Encrypt",
    "kms:GenerateDataKey"
  ],
  "Resource": "arn:aws:kms:region:account-id:key/key-id"
}

You can find the KMS key ID in the S3 bucket's properties (Server-side encryption section).

5Verify backend configuration uses correct profile

If using AWS profiles, ensure your backend configuration explicitly specifies the correct profile:

hcl
terraform {
  backend "s3" {
    bucket         = "your-terraform-state-bucket"
    key            = "terraform.tfstate"
    region         = "us-east-1"
    profile        = "your-aws-profile"
    encrypt        = true
  }
}

Then run:

bash
export AWS_PROFILE=your-aws-profile
terraform init

However, note that the profile parameter in backend configuration is not always reliable. Setting the AWS_PROFILE environment variable is more reliable.

6Check for bucket policy conflicts

Navigate to your S3 bucket in the AWS Console and check the Bucket Policy tab. Look for explicit Deny statements that might block access:

json
{
  "Effect": "Deny",
  "Principal": "*",
  "Action": "s3:*",
  "Resource": "*"
}

If you find restrictive policies, update them to allow your IAM principal. You may also need to check the bucket's Access Control List (ACL) settings.

7Enable Terraform debug logging

For more detailed error information, run Terraform with debug logging enabled:

bash
TF_LOG=DEBUG terraform init

This will show detailed AWS API calls and responses, helping identify the exact permission that is missing. Look for lines mentioning the specific S3 action that failed.

8For cross-account access, verify role assumption

If using cross-account access with role_arn, verify that:

1. The role exists in the target account
2. The role's trust policy allows the source account/user to assume it:

json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::source-account-id:user/user-name"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

3. Your IAM user in the source account has sts:AssumeRole permission
4. The role in the target account has the necessary S3 permissions

Advanced notes

The profile parameter in S3 backend configuration is unreliable across Terraform versions. Consider using environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_PROFILE) instead. When using Terraform workspaces, add a workspace_key_prefix to avoid permission issues with workspace creation. If you encounter this error on CI/CD, double-check that the service account or role has the correct permissions in the target AWS account. Some organizations use AWS Organizations SCPs (Service Control Policies) that can restrict S3 access at the organization level—verify these are not interfering. For highly secure environments, consider using temporary credentials via STS AssumeRole with specific session duration and external IDs.

Frequently asked questions

What does "AccessDenied" mean?
This error occurs when Terraform attempts to load your state file from an S3 backend but lacks the necessary AWS credentials or permissions. The AccessDenied error indicates that while Terraform successfully connected to AWS, the credentials being used do not have permission to read the S3 bucket or the state file within it. This is a critical error because Terraform cannot proceed without accessing the state file.
How do I fix "AccessDenied"?
Terraform cannot access the S3 backend state file due to insufficient AWS IAM permissions or misconfigured credentials. This prevents Terraform from reading or managing infrastructure state.
What causes "AccessDenied"?
IAM user or role lacks s3:GetObject permission on the state file IAM user or role lacks s3:ListBucket permission on the S3 bucket Terraform is using AWS credentials from environment variables or a default profile that differ from expected credentials
Is the "AccessDenied" error serious?
Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.

Official resources & further reading