AccessDenied (403 Forbidden)

AWS S3 Access Denied? Fix IAM Permissions That Look Right

S3 says AccessDenied even when your IAM policy looks perfect. We'll walk through the quick checks first, then dig into bucket policies, encryption, and public access blocks.

Start Here: 30-Second Fix

I know this error is infuriating. You've attached the right IAM policy, you can see the bucket in the console, but any request—CLI, SDK, or even the browser—throws AccessDenied (403 Forbidden). Before you pull your hair out, check the basics that trip up even seasoned engineers.

Check Your AWS Region

Yes, it sounds dumb, but I've seen this happen twice this month alone. If your CLI or SDK is pointing to the wrong region, S3 will happily return AccessDenied instead of a clearer error. Run aws s3 ls and confirm the region in your config. A quick aws configure will let you fix it.

Check the Bucket Name Spelling

One off-by-one character in the bucket name—like my-bucket vs my-buckett—gives you a 403, not a 404. Triple-check the exact bucket ARN in your IAM policy: arn:aws:s3:::my-bucket/*. If you used a wildcard, make sure it's placed correctly—arn:aws:s3:::my-bucket/* covers objects, but arn:aws:s3:::my-bucket covers the bucket itself. You often need both.

If you're using the AWS console, click the bucket name from the list instead of typing it. That saves you from typos.

If that didn't fix it, move to the next level.

Moderate Fix: 5 Minutes

Still locked out? The problem is almost certainly outside your IAM policy. Let's look at the other three suspects: bucket policy, ACLs, and S3 Public Access Block.

Check the Bucket Policy

A bucket policy can explicitly deny access even if your IAM allows it. In the S3 console, go to your bucket → PermissionsBucket Policy. Look for a Deny statement that might be catching your user or role. Common culprits are conditions like aws:SourceIp, aws:SecureTransport, or a principal that's too narrow.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:GetObject",
      "Resource": "arn:aws:s3:::my-bucket/*",
      "Condition": {
        "Bool": {
          "aws:SecureTransport": "false"
        }
      }
    }
  ]
}

That's a common one—it blocks HTTP requests. If you're testing with plain HTTP, you'll get denied. But if you're using HTTPS, that's not the issue.

Inspect Object-Level ACLs

If your bucket is set to Object Ownership: Bucket owner preferred (or if ACLs are enabled), an object uploaded by another account might not be accessible to you, even with full IAM permissions. This happened to me with a shared bucket—the object owner was a different account, and my IAM allowed everything, but I still got 403.

Check the object's Permissions tab. If the ACL looks off, you can try aws s3api put-object-acl --bucket my-bucket --key my-object --acl bucket-owner-full-control from the uploader's account, or simply re-upload with that ACL.

Review S3 Public Access Block

If you're trying to make objects public and they're not, the Block Public Access settings might be silently overriding your bucket policy. Go to your bucket's Permissions tab, then Block Public Access. If any of the four blocks are enabled, they'll deny public reads even if your bucket policy allows s3:GetObject for Principal: "*".

You can unblock if it's your own bucket and you truly want it public, but think hard before doing that.

Still no luck? Time to dig into the advanced stuff.

Advanced Fix: 15+ Minutes

If you've verified IAM, bucket policy, ACLs, and public access blocks, the culprit is often something you can't see in the console directly.

Check S3 Bucket Ownership and ACL Disablement

As of April 2023, AWS defaults to disabling ACLs for new buckets. If your bucket was created earlier, ACLs may still be active. But there's a quirk: if the bucket owner doesn't own the object, even the bucket owner can't access it without an explicit grant. The fix is to update the bucket to Object Ownership: Bucket owner enforced. This disables ACLs and gives the bucket owner full control over all objects.

aws s3api put-bucket-ownership-controls --bucket my-bucket --ownership-controls '{"Rules": [{"ObjectOwnership": "BucketOwnerEnforced"}]}'

This is a one-way door—you can enable it, but you can't revert to BucketOwnerPreferred afterward (you can, but it's messy). Only do this if you're confident you don't need ACLs.

Inspect AWS KMS Encryption Keys

If your bucket uses SSE-KMS, the request must have access to the KMS key. IAM permissions alone won't help—you also need kms:Decrypt (for GETs) and kms:GenerateDataKey (for PUTs) on the key. Attach those to your role or user. Check if the key policy allows your account or role. For cross-account scenarios, both the key policy and IAM policy must grant access.

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "kms:Decrypt",
        "kms:GenerateDataKey"
      ],
      "Resource": "arn:aws:kms:us-east-1:123456789012:key/your-key-id"
    }
  ]
}

You can test with aws s3 cp s3://my-bucket/my-file - --sse aws:kms --sse-kms-key-id your-key-id to see if the error message changes.

Look for Service Control Policies (SCPs)

If you're in an AWS Organization, an SCP at the root or OU level can deny S3 actions without you knowing. Go to AWS Organizations → Policies → SCPs and check if any policy denies s3:* or s3:GetObject for your account. This often affects new members of a governed organization.

I once spent an hour debugging a 403 only to find an SCP that required MFA for all S3 actions. Always check SCPs early if you're under an org.

Still Locked Out? Use These Debugging Commands

When you're stuck, make the error tell you more. Use the AWS CLI with --debug to see the exact request and response:

aws s3 ls s3://my-bucket --debug

Look for the <Error><Code>AccessDenied</Code> block. Sometimes the <Message> will hint at the cause, like “Access Denied because of bucket policy.”

You can also test with --no-sign-request to see if the bucket is publicly accessible, but that only works if the bucket allows it.

And if you've really exhausted everything, open a support case with AWS. They can see the eventual consistency and policy evaluation that you can't. But you've got a solid shot at fixing it yourself with these steps.

Related Errors in Server & Cloud
0X0000094F 0X0000094F: Source and destination on different servers fix E_FAIL (0x80004005) VirtualBox VM Black Screen on Boot — 3 Fixes 0X0000077D Fix RPC_X_PIPE_DISCIPLINE_ERROR (0x0000077d) in Server & Cloud 0x8007176D VM Migration Fails: Insufficient Resources on Host

Was this solution helpful?

EP
Erropedia Team
Tech Support Editors
The Erropedia editorial team researches and documents real-world tech errors from across Windows, Linux, macOS, networking, databases, cloud platforms, and more. Every solution is reviewed for accuracy and updated as software and systems evolve.