IAM DeleteConflict: "Cannot Delete Entity, Must Detach All Policies First" (and Every Other "Must ... First"), Fixed for Users, Roles, Groups and Policies, With Tested Cleanup Scripts, CloudFormation and Terraform

Logeshwaran
—

"Cannot delete entity, must detach all policies first" and its siblings ("must delete access keys first", "must delete policies first", "must remove roles from instance profile first") are IAM's DeleteConflict error (HTTP 409): you asked IAM to delete a user, role, group or policy that still has something attached to it, and IAM refuses to delete it out from under those attachments. The message names the first thing in the way. Here is the fact that explains why the same delete works in one place and fails in another: the IAM console cleans up the attachments for you, and nothing else does. Unlike the console, any programmatic delete requires you to remove the items attached to the user or role yourself, or the deletion fails. So the CLI, the SDKs, CloudFormation, Terraform and Ansible all hit this error on a user with an access key or a role with a policy, while the console button works. The fix is to remove the attachments in IAM's order, and this page gives you three tested scripts that do exactly that for a user, a role and a managed policy, plus the CloudFormation and Terraform versions of the same problem.

Jake's phone repair shop gave its weekend helper an AWS user last summer so he could update the price list in an S3 bucket. The helper left, and Ethan, Jake's developer friend, wrote a one-line cleanup in the shop's deployment script: delete the user. It failed with "must delete access keys first." He deleted the key; it failed again, now asking him to detach policies. Then the password, then the group. Jake, watching the fourth red line in a row, asked: "Is it going to tell us one thing at a time forever?" It nearly does, and that is why this page ends with a script that removes everything in one pass.

⚡ Quick Answer

• What it means: the user, role, group or policy still has things attached. The message names one of them; there may be more. Plain English.

• User: remove password, access keys, signing certificates, SSH keys, Git credentials, MFA devices, inline and attached policies, group memberships, then delete. Order + script.

• Role: delete inline policies, detach managed policies, remove it from instance profiles, then delete. Order + script.

• Managed policy: detach it everywhere, delete its non-default versions, then delete it (the default version goes with it). Order + script.

• CloudFormation stack stuck in DELETE_FAILED: something outside the stack attached a policy to its role. Detach it, retry the delete. Stack fix.

Also: groups · Terraform and Ansible · service-linked roles · server certificates · fixes by message.

New to IAM? Our plain-English guide to AWS IAM explains users, roles, groups and policies in about ten minutes. You can follow this page without it.

🧭 NEW HERE? READ THESE FIRST

New to IAM users, roles and policies? These five pages give you the words this one uses:

📌 Bookmark this; the three cleanup scripts are the part you will come back for.

What DeleteConflict means, and why the console never shows it

IAM objects hang off each other. A user can have a password, access keys, an MFA device, policies and group memberships. A role can have policies and can sit inside an instance profile that EC2 instances use. A managed policy can be attached to dozens of users, groups and roles, and can have up to five versions. IAM will not delete an object while anything still hangs off it, because that would leave the attachments pointing at nothing. The refusal is DeleteConflict, which AWS defines as a delete "rejected because it attempted to delete a resource that has attached subordinate entities," adding that "the error message describes these entities."

In the CLI it looks like this, and the part after the colon is the useful part:

An error occurred (DeleteConflict) when calling the DeleteUser operation: Cannot delete entity, must detach all policies first.

Two things make this error more annoying than it should be. First, it names one blocker at a time. A user with a key, a password and a policy fails three times, with three different messages, as you clear each one. That is what happened to Ethan. Second, the console hides it completely. When you delete a user or role in the IAM console, the console removes the keys, password, policies and memberships for you first, so you never see the error there. Every programmatic route (the AWS CLI, Python's boto3, CloudFormation, Terraform, the CDK, Ansible) calls the raw delete API, which does no cleanup. That is why "it works when I click delete" and "my script fails" are both true.

Jake: "So the console is a mover who empties the house before demolishing it, and the script just brings the bulldozer?"

Ethan: "And the bulldozer refuses while there's furniture inside. Fair enough, really. We just have to empty the house ourselves."

Every "must ... first" message and what it wants

MessageOnRemove with
must detach all policies firstUser, role, groupdetach-user-policy / detach-role-policy / detach-group-policy (managed policies)
must delete policies firstUser, role, groupdelete-user-policy / delete-role-policy / delete-group-policy (inline policies)
must delete access keys firstUserdelete-access-key
login profile, MFA, signing certificates, SSH keys, service credentialsUserdelete-login-profile, deactivate-mfa-device + delete-virtual-mfa-device, delete-signing-certificate, delete-ssh-public-key, delete-service-specific-credential
group membershipsUser, groupremove-user-from-group
must remove roles from instance profile firstRoleremove-role-from-instance-profile
Cannot delete a policy attached to entities / more than one versionManaged policyDetach everywhere, then delete-policy-version for the non-default ones
Cannot delete the default version of a policyPolicy versionDelete the policy itself; the default version goes with it
Certificate ... is currently in use by arn:aws:elasticloadbalancing:...Server certificateChange the load balancer's listener first

"Detach" and "delete" are not the same in IAM, and the message tells you which you need. Managed policies are separate objects you attach; you detach them, and the policy itself survives. Inline policies live inside one user, role or group; you delete them. "Must detach all policies first" means managed ones; "must delete policies first" means inline ones. Our IAM policy guide covers the difference.

See everything attached before you delete anything

Before you remove anything, list it. These read-only commands show everything that can block a user's delete; none of them changes anything:

U=old-helper
aws iam get-login-profile            --user-name $U          # error NoSuchEntity = no password
aws iam list-access-keys             --user-name $U
aws iam list-signing-certificates    --user-name $U
aws iam list-ssh-public-keys         --user-name $U
aws iam list-service-specific-credentials --user-name $U
aws iam list-mfa-devices             --user-name $U
aws iam list-user-policies           --user-name $U          # inline
aws iam list-attached-user-policies  --user-name $U          # managed
aws iam list-groups-for-user         --user-name $U

For a role, three lists cover it: list-role-policies (inline), list-attached-role-policies (managed) and list-instance-profiles-for-role. For a managed policy, list-entities-for-policy shows every user, group and role it is attached to, and list-policy-versions shows its versions.

One check before deleting a person's user or a working role: is it still in use? The IAM console's Last accessed tab, and aws iam get-role --role-name NAME --query Role.RoleLastUsed for roles, show recent activity (tracked for up to 400 days). If a key was used yesterday, something will break when you delete it. For a key that may have leaked, deactivating it first is the safe move; our leaked-key guide covers that order.

Deleting an IAM user: the order and a tested script

DeleteUser's own documentation lists what must go first: the password (login profile), access keys, signing certificates, SSH public keys, Git credentials (service-specific credentials), MFA devices, inline policies, attached managed policies, and group memberships. MFA devices take two steps for virtual devices: deactivate, then delete. Hardware devices only need deactivating. The order among these does not matter much; what matters is that all of them are gone before the final delete.

This script does the whole job. Run it once without --delete to see exactly what it would remove; run it again with --delete to do it:

#!/usr/bin/env bash
# Delete an IAM user and everything that blocks the delete, in the order IAM requires.
# Usage: ./delete-iam-user.sh USERNAME            (dry run: lists what would be removed)
#        ./delete-iam-user.sh USERNAME --delete   (does it)
set -euo pipefail
U="$1"; DO="${2:-}"
run(){ echo "+ aws $*"; if [ "$DO" = "--delete" ]; then aws "$@"; fi; }

aws iam get-login-profile --user-name "$U" >/dev/null 2>&1 && run iam delete-login-profile --user-name "$U"
for k in $(aws iam list-access-keys --user-name "$U" --query 'AccessKeyMetadata[].AccessKeyId' --output text); do
  run iam delete-access-key --user-name "$U" --access-key-id "$k"; done
for c in $(aws iam list-signing-certificates --user-name "$U" --query 'Certificates[].CertificateId' --output text); do
  run iam delete-signing-certificate --user-name "$U" --certificate-id "$c"; done
for k in $(aws iam list-ssh-public-keys --user-name "$U" --query 'SSHPublicKeys[].SSHPublicKeyId' --output text); do
  run iam delete-ssh-public-key --user-name "$U" --ssh-public-key-id "$k"; done
for c in $(aws iam list-service-specific-credentials --user-name "$U" --query 'ServiceSpecificCredentials[].ServiceSpecificCredentialId' --output text); do
  run iam delete-service-specific-credential --user-name "$U" --service-specific-credential-id "$c"; done
for m in $(aws iam list-mfa-devices --user-name "$U" --query 'MFADevices[].SerialNumber' --output text); do
  run iam deactivate-mfa-device --user-name "$U" --serial-number "$m"
  case "$m" in *:mfa/*) run iam delete-virtual-mfa-device --serial-number "$m";; esac; done
for p in $(aws iam list-user-policies --user-name "$U" --query 'PolicyNames[]' --output text); do
  run iam delete-user-policy --user-name "$U" --policy-name "$p"; done
for a in $(aws iam list-attached-user-policies --user-name "$U" --query 'AttachedPolicies[].PolicyArn' --output text); do
  run iam detach-user-policy --user-name "$U" --policy-arn "$a"; done
for g in $(aws iam list-groups-for-user --user-name "$U" --query 'Groups[].GroupName' --output text); do
  run iam remove-user-from-group --user-name "$U" --group-name "$g"; done
run iam delete-user --user-name "$U"
chmod +x delete-iam-user.sh
./delete-iam-user.sh old-helper            # dry run: prints the commands
./delete-iam-user.sh old-helper --delete   # removes everything, then the user

It needs bash and the AWS CLI v2, so it runs as-is on Linux, a Mac, and Windows through WSL or Git Bash. On a test setup, a plain delete-user on a user with a password, a key, a policy and a group failed with "Cannot delete entity, must detach all policies first," and the script removed everything and deleted the user in one pass. The caller needs the matching IAM permissions (iam:DeleteAccessKey, iam:DetachUserPolicy and so on); an administrator has them all.

Jake: "So instead of the computer telling us one thing at a time, we ask it for the whole list and clear it."

Ethan: "Exactly. Read the whole inventory, empty the house, then knock it down. One pass."

Deleting an IAM role: policies and instance profiles

A role blocks its delete with three kinds of attachment: inline policies, attached managed policies, and membership in an instance profile, the wrapper EC2 uses to hand a role to an instance. The instance-profile one is the surprise for most people, because the console creates and hides the instance profile when you create a role for EC2, so you never see it until the API complains:

An error occurred (DeleteConflict) when calling the DeleteRole operation: Cannot delete entity, must remove roles from instance profile first.
#!/usr/bin/env bash
# Delete an IAM role and everything that blocks the delete.
# Usage: ./delete-iam-role.sh ROLENAME [--delete]
set -euo pipefail
R="$1"; DO="${2:-}"
run(){ echo "+ aws $*"; if [ "$DO" = "--delete" ]; then aws "$@"; fi; }
for p in $(aws iam list-role-policies --role-name "$R" --query 'PolicyNames[]' --output text); do
  run iam delete-role-policy --role-name "$R" --policy-name "$p"; done
for a in $(aws iam list-attached-role-policies --role-name "$R" --query 'AttachedPolicies[].PolicyArn' --output text); do
  run iam detach-role-policy --role-name "$R" --policy-arn "$a"; done
for ip in $(aws iam list-instance-profiles-for-role --role-name "$R" --query 'InstanceProfiles[].InstanceProfileName' --output text); do
  run iam remove-role-from-instance-profile --instance-profile-name "$ip" --role-name "$R"; done
run iam delete-role --role-name "$R"

The script removes the role from its instance profiles but does not delete the profiles, on purpose. An instance profile can be in use by running instances, and AWS's warning on both DeleteRole and DeleteInstanceProfile is blunt: deleting a role or instance profile associated with a running instance breaks the applications on it. Check first with aws ec2 describe-iam-instance-profile-associations, and delete an unused profile afterward with aws iam delete-instance-profile --instance-profile-name NAME, which works only once no role is left inside it.

If you want a role to stop working but are not sure you can delete it yet, IAM offers a softer option: attach a policy that denies everything and revoke its active sessions from the console's role page. Nothing calling it will get anywhere, and you can undo it.

Deleting a managed policy: detach everywhere, then versions

A customer managed policy has two kinds of blockers: every user, group and role it is attached to, and every version besides the default. IAM keeps up to five versions of a policy, and delete-policy refuses while more than one exists. The default version is the exception in the other direction: delete-policy-version refuses to delete it ("Cannot delete the default version of a policy"), because it goes away with the policy itself. So the order is: detach everywhere, delete the non-default versions, then delete the policy.

#!/usr/bin/env bash
# Delete a customer managed policy: detach it everywhere, delete non-default versions, then the policy.
# Usage: ./delete-iam-policy.sh POLICY_ARN [--delete]
set -euo pipefail
P="$1"; DO="${2:-}"
run(){ echo "+ aws $*"; if [ "$DO" = "--delete" ]; then aws "$@"; fi; }
for u in $(aws iam list-entities-for-policy --policy-arn "$P" --query 'PolicyUsers[].UserName' --output text); do run iam detach-user-policy --user-name "$u" --policy-arn "$P"; done
for g in $(aws iam list-entities-for-policy --policy-arn "$P" --query 'PolicyGroups[].GroupName' --output text); do run iam detach-group-policy --group-name "$g" --policy-arn "$P"; done
for r in $(aws iam list-entities-for-policy --policy-arn "$P" --query 'PolicyRoles[].RoleName' --output text); do run iam detach-role-policy --role-name "$r" --policy-arn "$P"; done
for v in $(aws iam list-policy-versions --policy-arn "$P" --query 'Versions[?IsDefaultVersion==`false`].VersionId' --output text); do run iam delete-policy-version --policy-arn "$P" --version-id "$v"; done
run iam delete-policy --policy-arn "$P"

AWS managed policies (the ones whose ARN starts with arn:aws:iam::aws:policy/) cannot be deleted at all; you can only detach them. If a policy shows up in list-entities-for-policy attached to a role you do not recognize, find out what uses that role before detaching: it may be a pipeline or a service you forgot about.

Deleting a group

Groups are the simplest case, and the one people most often delete by accident, because a group's permissions reach everyone in it. A group must have no users and no policies before it can be deleted. Remove each member with aws iam remove-user-from-group, delete inline policies with delete-group-policy, detach managed ones with detach-group-policy, then aws iam delete-group --group-name NAME. The users themselves are untouched; they just lose the permissions the group gave them, which is worth telling them before you do it.

In one go, for a group called support:

G=support
for u in $(aws iam get-group --group-name $G --query 'Users[].UserName' --output text); do aws iam remove-user-from-group --group-name $G --user-name $u; done
for p in $(aws iam list-group-policies --group-name $G --query 'PolicyNames[]' --output text); do aws iam delete-group-policy --group-name $G --policy-name $p; done
for a in $(aws iam list-attached-group-policies --group-name $G --query 'AttachedPolicies[].PolicyArn' --output text); do aws iam detach-group-policy --group-name $G --policy-arn $a; done
aws iam delete-group --group-name $G

CloudFormation: DELETE_FAILED on an IAM role

The most-read version of this error is a CloudFormation stack that will not delete, or a rollback that stops, with the role resource showing:

Cannot delete entity, must detach all policies first. (Service: AmazonIdentityManagement; Status Code: 409; Error Code: DeleteConflict)

CloudFormation deletes what it created, in reverse dependency order, and it does that correctly for policies defined in the same stack. The error almost always means something outside the stack attached a policy to the stack's role: someone in the console, another stack, a Terraform run, a security tool that adds a policy to every role, or a pipeline step. CloudFormation does not know about that attachment, so it does not remove it, and IAM refuses the role's delete.

  1. Find the outside attachment: aws iam list-attached-role-policies --role-name ROLE and list-role-policies, and compare with what the template defines.
  2. Detach or delete what the template does not own (after confirming nothing else needs it on this role).
  3. Retry the stack delete. For a stack stuck in DELETE_FAILED, a second delete usually completes; if you must leave the role, the console's delete dialog lets you retain that resource, and the CLI takes --retain-resources for stacks in that state.

The design fix, which the person behind the most-read question landed on: attach policies inside the role resource (ManagedPolicyArns or Policies on the AWS::IAM::Role) rather than in a separate resource that another stack or tool might also touch. A stack stuck in a failed rollback has its own fix order, covered in our ROLLBACK_COMPLETE guide.

Terraform, CDK and Ansible

Terraform has a switch for each case, both off by default:

  • force_detach_policies = true on aws_iam_role detaches any policies the role has before destroying it, including ones attached outside Terraform.
  • force_destroy = true on aws_iam_user destroys the user even when it has access keys, a login profile or MFA devices that Terraform did not create.

Both exist because the API will not do the cleanup. Turn them on for resources whose whole life Terraform owns; leave them off for anything a person might attach something to on purpose, so a destroy does not silently remove access someone relies on. One Terraform-specific trap: if policies are attached with the separate aws_iam_policy_attachment resource and you rename or move the role or user, set the force option and apply it before the rename, or the replacement fails with this error.

CDK generates CloudFormation, so the CloudFormation section applies. A role imported into one stack with Role.fromRoleArn and given extra policies by another stack is the usual CDK route to an outside attachment.

Ansible users report "Cannot delete entity, must delete access keys first" from the IAM user module: the module deletes the user without removing its keys. Remove the keys (and the login profile) in earlier tasks, or call the script above from a shell task.

Two special cases: service-linked roles and server certificates

Service-linked roles. Roles named AWSServiceRoleFor... belong to an AWS service, which created them and decides when they can go. You delete them through that service, often by removing whatever used the role (the last load balancer, the last cluster), after which the service deletes the role itself or lets you. Deleting one directly fails with a message saying it is in use by the service. Leave them alone unless you are retiring the service completely.

Server certificates in use by a load balancer. IAM also stores older SSL server certificates. Deleting one that a Classic or Application Load Balancer listener still uses fails with a DeleteConflict naming the load balancer's ARN: "Certificate: ... is currently in use by arn:aws:elasticloadbalancing:...". Point the listener at a different certificate (most teams move to ACM certificates for this), then delete the old one with aws iam delete-server-certificate.

When the name will not go away: the other side of this error

Deleting an IAM entity frees its name, so you can create a new one with the same name right after. If you are deleting a role only because a create failed with "already exists," that is the opposite error, with its own safer fixes in our EntityAlreadyExists guide. Keep in mind that a new role with the old name is a new identity: resource policies (an S3 bucket policy, a KMS key policy) that named the old role's ARN may need updating, because IAM tracks roles by a unique ID behind the name.

If you plan to recreate the role, save its definition before you delete it: aws iam get-role --role-name NAME for the trust policy, plus the inline and attached policy lists from the commands above. Then the new role starts as an exact copy, and you only have to fix the resource policies that pointed at the old one.

The ten-minute fix order

  1. Read the message after the colon: it names the first blocker.
  2. List everything attached (the read-only commands above) so you clear it in one pass, not five.
  3. Check the entity is unused: Last accessed, RoleLastUsed, instance profile associations.
  4. Run the matching script dry, read its list, then run it with --delete.
  5. For a stuck CloudFormation stack, remove the attachment made outside the stack, then retry the delete.
  6. For Terraform, set force_detach_policies or force_destroy where Terraform owns the whole resource.

Most of that is reading, not deleting. The only irreversible step is the last one, which is why the scripts default to a dry run: you see the full list of what goes before anything goes.

Fixes by message

You seeDo this
must detach all policies firstlist-attached-*-policies, then detach-*-policy for each
must delete policies firstlist-*-policies, then delete-*-policy for each inline policy
must delete access keys firstlist-access-keys, delete-access-key
login profile / MFA / certificates / SSH keysRun the user script: it clears all of them
must remove roles from instance profile firstremove-role-from-instance-profile; check running instances first
Cannot delete a policy attached to entitieslist-entities-for-policy, detach from each
This policy has more than one versionDelete the non-default versions, then the policy
Cannot delete the default version of a policyDelete the policy instead
Stack DELETE_FAILED on a roleDetach the outside policy, retry the delete
Certificate is currently in use by ... elasticloadbalancingChange the listener's certificate, then delete

Frequently asked questions about IAM DeleteConflict

What does DeleteConflict mean in AWS IAM?

You tried to delete a user, role, group, policy or instance profile that still has something attached, such as policies, access keys or an instance profile. IAM returns HTTP 409 and names the first blocker in the message.

Why can I delete an IAM user in the console but not with the CLI?

The console removes the user's password, keys, policies and group memberships before deleting it. The DeleteUser API does no cleanup, so the CLI, SDKs, CloudFormation and Terraform must remove each attachment first.

How do I fix "Cannot delete entity, must detach all policies first"?

List the managed policies attached to the user, role or group with list-attached-user-policies, list-attached-role-policies or list-attached-group-policies, detach each one, then delete the entity.

What is the difference between "must delete policies first" and "must detach all policies first"?

"Delete policies" refers to inline policies, which live inside the entity and are deleted. "Detach all policies" refers to managed policies, which are separate objects and are detached; the policy itself survives.

How do I fix "Cannot delete entity, must delete access keys first"?

Run aws iam list-access-keys --user-name NAME, then aws iam delete-access-key for each key ID. Check the key's last use first if anything might still depend on it.

How do I fix "must remove roles from instance profile first"?

Run aws iam list-instance-profiles-for-role, then aws iam remove-role-from-instance-profile for each profile. Make sure no running EC2 instance uses the profile, or its applications lose their permissions.

How do I delete an IAM user with everything attached?

Remove the password, access keys, signing certificates, SSH keys, service-specific credentials, MFA devices, inline policies, attached policies and group memberships, then delete the user. The script on this page does it in one pass.

How do I delete an IAM policy that has multiple versions?

Detach it from every user, group and role, delete each version where IsDefaultVersion is false with delete-policy-version, then delete the policy, which removes the default version with it.

Why can't I delete the default version of an IAM policy?

The default version is deleted together with the policy. Delete the other versions first, then call delete-policy.

Why does my CloudFormation stack fail to delete an IAM role?

Usually a policy was attached to the role outside the stack, by a person, another stack or a tool. CloudFormation does not remove what it did not create. Detach it, then retry the stack delete.

How do I make Terraform delete a role with attached policies?

Set force_detach_policies = true on the aws_iam_role resource. For users with keys, a login profile or MFA devices created outside Terraform, set force_destroy = true on aws_iam_user.

Can I delete an IAM role that an EC2 instance is using?

IAM will let you once it is removed from the instance profile, but the instance's applications lose their permissions immediately. Check with aws ec2 describe-iam-instance-profile-associations first.

How do I delete an IAM group?

Remove every user with remove-user-from-group, delete inline policies and detach managed policies, then run aws iam delete-group. The users remain but lose the group's permissions.

Can I delete AWS managed policies?

No. Policies with ARNs starting arn:aws:iam::aws:policy/ belong to AWS. You can only detach them from your users, groups and roles.

How do I delete a service-linked role?

Through the service that owns it, usually by removing the last resource that uses it. Deleting it directly fails while the service still needs it.

How do I check if an IAM role is still used before deleting it?

Run aws iam get-role --role-name NAME --query Role.RoleLastUsed or open the role's Last accessed tab in the console. IAM tracks role activity for up to 400 days.

Does deleting an IAM role break bucket policies that name it?

Policies that named the role's ARN stop matching it, and a new role with the same name is a different identity behind the scenes. Update those resource policies after recreating a role.

What does DeleteConflict mean for a server certificate?

A load balancer listener still uses the certificate. Switch the listener to another certificate, then delete the old one with aws iam delete-server-certificate.

Ethan replaced the one-line delete in the shop's script with the user cleanup script, ran it dry, read the list (one password, one key, one policy, one group), and ran it for real. The old helper's access was gone in four seconds. Jake asked whether the script would work for the next helper too. "For anyone," said Ethan. "That's the point. The computer was never being difficult. It just wanted the house empty first."

📌 If you keep one line from this page

DeleteConflict means the IAM object still has things attached, and only the console removes them for you: list everything, remove it in one pass, then delete, and check the role or key is unused before you do.

Detach = managed policies · delete = inline · roles hide in instance profiles · policies: versions first, default goes last · Terraform: force_detach_policies, force_destroy.

Revision note. Written October 16, 2026, with all three scripts run against a test IAM setup. "A place for everything, and everything in its place," the old saying goes; IAM simply insists the places are empty before it closes them.

Related