Fix LDAP Insufficient Access Error 50 in 389 Directory Server

Tested on Rocky Linux 10.2 (Red Quartz)
Package 389-ds-base 3.2.0-8.el10_2
Applies to RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, Fedora
Privilege sudo or root
Scope Fix LDAP error 50: ACIs, group membership, deny rules, effective rights, and access logs. Does not cover unrelated LDAP error codes.
Related guides Install 389 Directory Server
ACI examples
Get Effective Rights
dsconf commands
Fix LDAP invalid credentials error 49

LDAP result code 50 means the authorization identity used for the operation does not have sufficient access rights. In this lab, the user bind succeeds and 389 Directory Server rejects the later modify during ACI evaluation. Anonymous operations can also return error 50 when anonymous access is not permitted.

Clients usually print:

text
ldap_modify: Insufficient access (50)

The same code appears on add, delete, modify DN, and some extended operations:

text
ldap_add: Insufficient access (50)
text
ldap_delete: Insufficient access (50)

389 DS often adds a more specific line naming the missing privilege:

text
additional info: Insufficient 'write' privilege to the 'telephoneNumber' attribute of entry 'uid=user2,ou=people,dc=example,dc=com'.

RFC 4511 defines result code 50 as insufficientAccessRights. It does not require a successful authenticated bind first. Read the diagnostic text alongside the number. The additional info line usually names the attribute, entry, or operation that failed ACI evaluation.

When the bind itself fails with error 49, work through Separate error 49 from error 50 before editing ACIs. When the server returns error 53 with messages such as Password must be changed, Server is read-only, or RootDN access control violation, use fix LDAP unwilling to perform error 53 instead of editing ACIs.

LDAP operation Main ACI rights to inspect
Modify an attribute write on the target attribute
Add an entry add on the new entry plus permitted writes to its attributes
Delete an entry delete on the target entry; attribute-value restrictions can also affect deletion
Rename an entry write on the entry and the old or new RDN attributes
Move an entry moddn with matching target_from and target_to, plus required RDN attribute rights
Search search to match attributes and read to return values

This guide demonstrates attribute write failures. For add, delete, or modify-DN errors, run Get Effective Rights against the same subject and target but inspect the operation-specific entry and attribute rights described in the effective rights chapter.

Use the cause table below to jump to the fix that matches your situation. ACI design, macro rules, self-service policy, and delegated administration stay in the linked chapters.

IMPORTANT
This article covers LDAP result code 50 and closely related authorization failures in 389 Directory Server. It does not cover Microsoft Active Directory authorization subcodes, bind failures that return error 49, or TLS handshake problems that fail before any bind is attempted.

Examples use instance ldap1 on ldap1.example.com:389 with suffix dc=example,dc=com, users uid=user1 and uid=user2 under ou=people, and delegated group cn=profile-editors,ou=Groups. The lab includes self-service ACIs from self-service password and profile ACIs. Create matching test entries before you follow the modify exercises, or substitute your own lab accounts.


Causes and fixes at a glance

Symptom or situation Likely cause Fix
ldapwhoami fails before any modify Authentication problem, not ACI Separate error 49 from error 50
User cannot change another user's attribute Self-only ACI (ldap:///self) Fix self-service scope
Delegated rule exists but modify still fails groupdn mismatch or missing membership Fix groupdn membership
Allow rule looks correct but write still denied Deny rule overrides allow Fix deny rule precedence
Need attribute-level proof before editing ACIs GER not run or wrong subject DN Inspect rights with Get Effective Rights
Failure only visible in application logs Access log not checked Read the access log
Broad policy design still unclear Missing baseline ACI examples ACI examples and advanced ACI targets

The access log at /var/log/dirsrv/slapd-INSTANCE/access pairs each operation request with its result on the same conn= and op= numbers. A denied modify pair looks like this:

text
conn=35 op=1 MOD dn="uid=user2,ou=people,dc=example,dc=com"
conn=35 op=1 RESULT err=50 tag=103 nentries=0

Search recent failures with the denied operation request included:

bash
sudo grep -B1 'RESULT err=50' /var/log/dirsrv/slapd-ldap1/access | tail -10

The -B1 flag includes the MOD, ADD, DEL, or MODRDN request immediately before each RESULT err=50 line. Use the full connection trace in Read the access log to confirm which identity authenticated before the denied operation.


Separate error 49 from error 50

Confirm the bind identity with the ldapwhoami command before you change ACIs. A password bind that fails authentication never reaches authorization.

bash
ldapwhoami -x -H ldap://ldap1.example.com:389 -D "uid=user1,ou=people,dc=example,dc=com" -y /root/user1.pw

Sample output:

output
dn: uid=user1,ou=people,dc=example,dc=com

A successful bind prints the entry DN. When this command returns error 49, stop here and follow fix LDAP invalid credentials error 49.

Repeat the failing operation only after ldapwhoami succeeds. Authorization diagnostics assume the bind identity in -D is the identity Directory Server evaluates against ACIs.


Inspect ACIs on the target and parents

ACI inspection uses the ldapsearch command on the target entry and each parent container.

List ACIs on the target entry first:

bash
ldapsearch -LLL -o ldif-wrap=no -x -H ldap://ldap1.example.com:389 -D "cn=Directory Manager" -y /root/dm.pw -b "uid=user2,ou=people,dc=example,dc=com" -s base "(objectClass=*)" aci

A user entry often carries no aci values. The next search shows the rules on the parent container:

bash
ldapsearch -LLL -o ldif-wrap=no -x -H ldap://ldap1.example.com:389 -D "cn=Directory Manager" -y /root/dm.pw -b "ou=People,dc=example,dc=com" -s base "(objectClass=*)" aci

Sample output (trimmed):

output
dn: ou=People,dc=example,dc=com
aci: (targetattr="mail || telephoneNumber || mobile || displayName || preferredLanguage || postalAddress")(version 3.0; acl "Self write profile attributes"; allow (write) userdn="ldap:///self";)

Finish on the suffix in case a broader rule applies above the container:

bash
ldapsearch -LLL -o ldif-wrap=no -x -H ldap://ldap1.example.com:389 -D "cn=Directory Manager" -y /root/dm.pw -b "dc=example,dc=com" -s base "(objectClass=*)" aci

Sample output (trimmed):

output
dn: dc=example,dc=com
aci: (targetattr="dc || description || objectClass")(targetfilter="(objectClass=domain)")(version 3.0; acl "Enable anyone domain read"; allow (read, search, compare)(userdn="ldap:///anyone");)

ACIs inherited from parent entries participate in the decision. An allow on ou=People can therefore be blocked by an applicable deny on the suffix. ACI placement determines scope, but applicable rules are evaluated together by their semantics rather than by list order alone.


Fix self-service scope

Self-service ACIs commonly use userdn="ldap:///self". That bind rule matches only when the target entry is the same as the authenticated user. A user who may edit their own telephoneNumber still receives error 50 on another account.

Save a cross-account modify attempt as /tmp/user2-tel.ldif:

ldif
dn: uid=user2,ou=people,dc=example,dc=com
changetype: modify
replace: telephoneNumber
telephoneNumber: +1-555-9999

Run the modify as user1 with the ldapmodify command:

bash
ldapmodify -x -H ldap://ldap1.example.com:389 -D "uid=user1,ou=people,dc=example,dc=com" -y /root/user1.pw -f /tmp/user2-tel.ldif

Sample output:

output
ldap_modify: Insufficient access (50)
	additional info: Insufficient 'write' privilege to the 'telephoneNumber' attribute of entry 'uid=user2,ou=people,dc=example,dc=com'.

modifying entry "uid=user2,ou=people,dc=example,dc=com"

The bind succeeded; the self-write rule does not apply across accounts.

ldap:///self is correct for profile self-service. It is not a bug when cross-account writes fail.

Verify the same user can still update their own entry. Save /tmp/user1-tel.ldif:

ldif
dn: uid=user1,ou=people,dc=example,dc=com
changetype: modify
replace: telephoneNumber
telephoneNumber: +1-555-0202

Apply it as user1:

bash
ldapmodify -x -H ldap://ldap1.example.com:389 -D "uid=user1,ou=people,dc=example,dc=com" -y /root/user1.pw -f /tmp/user1-tel.ldif

Sample output:

output
modifying entry "uid=user1,ou=people,dc=example,dc=com"

When self-modify works but cross-account work fails, add a separate delegated ACI with groupdn or an explicit userdn. See delegated administration for scoped help-desk and operator roles.


Inspect rights with Get Effective Rights

Get Effective Rights (GER) shows how ACIs combine for a subject on a target entry. Run this step while only self-service ACIs apply, before you add delegated or deny rules in the sections below.

Evaluate user1 on user2:

bash
ldapsearch -LLL -o ldif-wrap=no -x -H ldap://ldap1.example.com:389 -D "cn=Directory Manager" -y /root/dm.pw -b "uid=user2,ou=people,dc=example,dc=com" -s base -E '!1.3.6.1.4.1.42.2.27.9.5.2=:dn:uid=user1,ou=people,dc=example,dc=com' "(objectClass=*)" telephoneNumber mail

Sample output:

output
dn: uid=user2,ou=people,dc=example,dc=com
telephoneNumber: +1-555-9999
mail: user2@example.com
entryLevelRights: none
attributeLevelRights: telephoneNumber:none, mail:none

telephoneNumber:none confirms no write, read, search, or compare rights for user1 on user2 under the self-service policy alone.

After a deny rule is in place, GER reports telephoneNumber:none for the subject even when an allow rule exists elsewhere on the same attribute. Pair GER with a live ldapmodify as the subject. Full syntax and interpretation codes are in test ACI permissions with Get Effective Rights.


Fix groupdn membership

Delegated writes often use groupdn="ldap:///cn=GROUP,...". The bind DN must be listed on the group entry, and the groupdn value must identify that same group entry.

Confirm group membership:

bash
ldapsearch -LLL -x -H ldap://ldap1.example.com:389 -D "cn=Directory Manager" -y /root/dm.pw -b "cn=profile-editors,ou=Groups,dc=example,dc=com" -s base "(objectClass=*)" member

Sample output:

output
dn: cn=profile-editors,ou=Groups,dc=example,dc=com
member: uid=user1,ou=people,dc=example,dc=com

user1 is a member. An ACI that references cn=ldap-editors instead would not match even when the human-readable group name looks similar.

Add a delegated write rule for profile editors on telephoneNumber. Save /tmp/editors-aci.ldif:

ldif
dn: ou=People,dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr="telephoneNumber")(target="ldap:///uid=*,ou=People,dc=example,dc=com")(version 3.0; acl "Editors write telephoneNumber"; allow (write) groupdn="ldap:///cn=profile-editors,ou=Groups,dc=example,dc=com";)

Apply as Directory Manager:

bash
ldapmodify -x -H ldap://ldap1.example.com:389 -D "cn=Directory Manager" -y /root/dm.pw -f /tmp/editors-aci.ldif

Sample output:

output
modifying entry "ou=People,dc=example,dc=com"

Retry the cross-account modify as user1:

bash
ldapmodify -x -H ldap://ldap1.example.com:389 -D "uid=user1,ou=people,dc=example,dc=com" -y /root/user1.pw -f /tmp/user2-tel.ldif

Sample output:

output
modifying entry "uid=user2,ou=people,dc=example,dc=com"

Confirm the new value as user2:

bash
ldapsearch -LLL -x -H ldap://ldap1.example.com:389 -D "uid=user2,ou=people,dc=example,dc=com" -y /root/user2.pw -b "uid=user2,ou=people,dc=example,dc=com" -s base "(objectClass=*)" telephoneNumber

Sample output:

output
dn: uid=user2,ou=people,dc=example,dc=com
telephoneNumber: +1-555-9999

When membership is correct but the modify still fails, compare the groupdn with the DN returned by ldapsearch. Confirm the group RDN, parent containers, suffix, and membership attribute rather than relying on the group's display name.


Fix deny rule precedence

389 Directory Server evaluates applicable ACIs by their semantics. A matching deny takes precedence over an allow on the same target, regardless of where each rule is stored.

Add a deny rule on the same attribute. Save /tmp/deny-tel.ldif:

ldif
dn: ou=People,dc=example,dc=com
changetype: modify
add: aci
aci: (targetattr="telephoneNumber")(target="ldap:///uid=*,ou=People,dc=example,dc=com")(version 3.0; acl "Deny telephoneNumber writes"; deny (write) userdn="ldap:///anyone";)

Apply as Directory Manager:

bash
ldapmodify -x -H ldap://ldap1.example.com:389 -D "cn=Directory Manager" -y /root/dm.pw -f /tmp/deny-tel.ldif

Sample output:

output
modifying entry "ou=People,dc=example,dc=com"

Retry the delegated modify:

bash
ldapmodify -x -H ldap://ldap1.example.com:389 -D "uid=user1,ou=people,dc=example,dc=com" -y /root/user1.pw -f /tmp/user2-tel.ldif

Sample output:

output
ldap_modify: Insufficient access (50)
	additional info: Insufficient 'write' privilege to the 'telephoneNumber' attribute of entry 'uid=user2,ou=people,dc=example,dc=com'.

Error 50 returns even though the profile-editors allow rule is still present. Remove or narrow the deny rule so it no longer matches the intended exception. When selected identities must retain access, add an exclusion to the deny bind rule rather than adding another allow at a lower or more specific target. Document deny rules beside their matching allows in change tickets so operators do not chase group membership alone.

Remove the demonstration deny rule

The broad deny blocks later lab work until you remove it. Save /tmp/remove-deny-tel.ldif:

ldif
dn: ou=People,dc=example,dc=com
changetype: modify
delete: aci
aci: (targetattr="telephoneNumber")(target="ldap:///uid=*,ou=People,dc=example,dc=com")(version 3.0; acl "Deny telephoneNumber writes"; deny (write) userdn="ldap:///anyone";)

Apply as Directory Manager:

bash
ldapmodify -x -H ldap://ldap1.example.com:389 -D "cn=Directory Manager" -y /root/dm.pw -f /tmp/remove-deny-tel.ldif

Sample output:

output
modifying entry "ou=People,dc=example,dc=com"

Retry the delegated modify to confirm the group allow works again:

bash
ldapmodify -x -H ldap://ldap1.example.com:389 -D "uid=user1,ou=people,dc=example,dc=com" -y /root/user1.pw -f /tmp/user2-tel.ldif

Sample output:

output
modifying entry "uid=user2,ou=people,dc=example,dc=com"

The delegated profile-editors ACI remains in place for later exercises. Delete it separately when you finish the lab.


Read the access log

The access log ties a failed result code to the authenticated DN and operation type. Trigger a failing modify, then search for the denied operation:

bash
sudo grep -B1 'RESULT err=50' /var/log/dirsrv/slapd-ldap1/access | tail -10

Sample output (trimmed):

output
conn=35 op=1 MOD dn="uid=user2,ou=people,dc=example,dc=com"
conn=35 op=1 RESULT err=50 tag=103 nentries=0

The line before RESULT err=50 is normally the denied operation request, not the earlier bind result. Inspect the full connection using the conn= value from that pair:

bash
sudo grep 'conn=35 ' /var/log/dirsrv/slapd-ldap1/access | tail -10

Sample output (trimmed):

output
conn=35 op=0 BIND dn="uid=user1,ou=people,dc=example,dc=com" method=128 version=3
conn=35 op=0 RESULT err=0 tag=97 nentries=0 dn="uid=user1,ou=people,dc=example,dc=com"
conn=35 op=1 MOD dn="uid=user2,ou=people,dc=example,dc=com"
conn=35 op=1 RESULT err=50 tag=103 nentries=0

op=0 with err=0 and a dn= field is the successful bind. op=1 with err=50 is the denied modify on the same connection. When several clients connect at once, match conn= and op= numbers rather than relying on wall-clock time alone.


Troubleshooting

Symptom Likely cause Fix
Error 49 on ldapwhoami Wrong password or bind DN Separate error 49 from error 50
Error 50 only on one attribute Missing targetattr or self-only scope Add attribute to targetattr; use delegated groupdn for cross-account work
Group member but error 50 persists Wrong groupdn DN or deny rule Compare group DN to ACI; remove or narrow deny
GER shows write but ldapmodify returns 50 Wrong GER subject, target, attribute, or endpoint; operation needs additional rights Repeat GER against the same server and exact target, then inspect the denied operation and applicable parent ACIs
Anonymous search works; modify fails Anonymous read allowed; write requires authenticated allow Expected behavior — add write ACI for the bind identity
Change applied but clients still fail Editing the wrong instance, suffix, target, or parent entry Confirm the -H host and port, suffix DN, ACI target, and the entry on which the ACI was stored

References


Summary

LDAP error 50 in 389 Directory Server means the authorization identity lacks sufficient rights for the requested operation. Confirm authenticated binds with ldapwhoami when error 49 is possible, read the additional info line for the missing attribute or entry right, list ACIs on the target and its parents, use Get Effective Rights to see effective attribute codes, and check the access log for the denied operation and its connection trace. Separate self-service ldap:///self rules from delegated groupdn policy, and remember that a matching deny overrides an allow regardless of rule placement.


Frequently Asked Questions

1. What does LDAP error 50 mean in 389 Directory Server?

Error 50 means the authorization identity does not have sufficient rights for the requested entry, attribute, or operation. In a typical authenticated workflow, the bind succeeds but ACI evaluation rejects the later search, add, modify, delete, or rename operation. Anonymous operations can also return error 50 when anonymous access is not permitted.

2. What is the difference between LDAP error 49 and error 50?

Error 49 is an authentication failure during a bind. Error 50 means the authorization identity—authenticated or anonymous—does not have sufficient rights for the requested operation. If ldapwhoami fails with error 49, fix credentials first. If the bind succeeds but ldapmodify returns error 50, inspect ACIs and group membership.

3. Why does ldapmodify return insufficient access when the user is in the group?

Confirm that the ACI groupdn identifies the actual group entry and that the bind DN is present in the group membership attribute. A case-only DN difference is normally normalized, but the group hierarchy and attribute values must identify the same entry. A matching deny rule can override the group-based allow.

4. How do I see which ACI blocked an operation?

Search ACIs on the target entry and its parents with ldapsearch, then use Get Effective Rights to see attribute-level codes for the bind DN on the target entry. Pair that with grep on the access log for RESULT err=50 lines after a failed modify or add.

5. Can Get Effective Rights show write permission when ldapmodify still fails?

Yes. First confirm that GER used the same subject DN, target entry, attribute, and server as the live operation. Some operations also require rights beyond one attribute—for example, add, delete, and modify-DN have different entry-level and attribute-level requirements. GER evaluates ACIs; a live operation remains the final test.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)