Static groups with thousands of member or uniqueMember values can make reads, searches, and incremental updates expensive. The MemberOf plug-in adds reverse membership on user entries whenever static group membership changes, and nested groups force additional graph traversal that scales with group size and nesting depth.
This guide covers the complete large static-group performance workflow: inventorying heavy groups, generating reproducible test data, configuring safe membership indexes, benchmarking reads and modifications, tuning MemberOf scope and nested handling, running fixup tasks safely, and monitoring plug-in and replication overhead.
Before you start:
- Install 389 Directory Server — running instance (
ldap1ondc=example,dc=comin this lab) - Manage users and groups — static group creation and membership attributes
- Configure the 389 Directory Server memberOf Plugin — baseline MemberOf enablement
- Configure 389 Directory Server Indexes for Faster LDAP Searches — general index types and reindex tasks
Tested on: Rocky Linux 10.2; 389 Directory Server 3.2.0.
Understand why large LDAP groups become expensive
The following are example benchmark tiers for this guide, not product limits or official size classifications:
Small group: 100 members
Medium group: 5,000 members
Large group: 50,000 members
Very large group: 100,000 or more members| Operation | Large-group cost |
|---|---|
| Read complete group | Transfers and decodes every membership value |
| Search for a member DN | Depends on a suitable equality index |
| Add one member | Updates the group entry and related indexes |
| Remove one member | Searches and updates the multi-valued attribute |
| Replace all members | Rewrites a very large value set |
| MemberOf processing | Updates reverse membership on affected entries |
| Referential Integrity | Searches for and updates references after delete or rename |
| Replication | Transfers membership modifications to other replicas |
| Export and import | Processes the complete multi-valued entry |
| Fixup task | Recalculates membership across many entries and groups |
The bottleneck may be any combination of:
Group entry size
Membership indexes
Enabled plug-ins
Nested membership
Replication
Client result handlingDo not assume every large-group problem is a database cache issue. Measure reads, indexed searches, incremental modifications, and plug-in-generated writes separately.
Choose the appropriate group design
| Design | Membership storage | Best use |
|---|---|---|
groupOfNames |
member DNs |
Common static LDAP groups |
groupOfUniqueNames |
uniqueMember DNs |
Static DN membership with optional uniqueness component |
| POSIX group | memberUid names |
Unix account integration |
| Dynamic group | LDAP URL and filter | Membership calculated from entry attributes |
| Auto Membership | Static members generated from rules | Applications requiring stored membership |
| Roles | Role attributes | Directory Server policy and access workflows |
The primary trade-off:
Static group:
Stores an explicit member list that can be retrieved directly,
although transferring a very large list remains expensive.
Dynamic group:
No huge stored member list
but membership must be calculated from a filter.Do not replace every static group with a dynamic group. Confirm the application supports filter-based membership and does not require an explicit member or uniqueMember list on the group entry.
memberOf values through the MemberOf plug-in. Applications that depend on reading memberOf from user entries may therefore require static groups or application-side evaluation of the dynamic group filter.
New entries in this section are added with the ldapadd command.
Inventory largest groups and generate test data
Export static groups with LDIF wrapping disabled so long DNs are not split across continuation lines:
ldapsearch -LLL -o ldif-wrap=no -Y EXTERNAL -H ldapi://%2Frun%2Fslapd-ldap1.socket -b "ou=Groups,dc=example,dc=com" -s sub "(|(objectClass=groupOfNames)(objectClass=groupOfUniqueNames))" dn member uniqueMember > /tmp/groups-membership.ldifCount membership values per group entry:
awk 'BEGIN{RS="";FS="\n"}{dn="";members=0;attribute="";for(i=1;i<=NF;i++){if($i~/^dn: /){dn=substr($i,5)}else if($i~/^member: /){members++;attribute="member"}else if($i~/^uniqueMember: /){members++;attribute="uniqueMember"}}if(members>0)printf "%10d\t%-12s\t%s\n",members,attribute,dn}' /tmp/groups-membership.ldif | sort -nr512 member cn=all-employees,ou=Groups,dc=example,dc=com
2 member cn=full-time-employees,ou=Groups,dc=example,dc=com
2 member cn=engineering-admins,ou=Groups,dc=example,dc=com
1 uniqueMember cn=ops-unique,ou=Groups,dc=example,dc=com
1 member cn=developers,ou=Groups,dc=example,dc=comThe first column is the current membership-value count. -o ldif-wrap=no prevents wrapped LDIF lines from corrupting the count. This export does not show modification frequency—derive that from access-log analysis if you need it.
Build a worksheet from the sorted output:
| Group DN | Attribute | Members |
|---|---|---|
cn=all-employees,ou=Groups,dc=example,dc=com |
member |
512 |
cn=full-time-employees,ou=Groups,dc=example,dc=com |
member |
2 |
cn=ops-unique,ou=Groups,dc=example,dc=com |
uniqueMember |
1 |
Also note groups nested inside other groups, users belonging to many groups, groups modified or retrieved frequently, groups maintained by Auto Membership, and groups processed by Referential Integrity. Do not expose a complete membership export outside a protected test environment.
Generate reproducible large-group datasets
Use a dedicated test suffix or disposable backend. Confirm that ou=Groups and ou=People already exist before loading generated entries. Confirm generator syntax on your installed release:
Offline instance work in this section uses dsctl commands.
dsctl ldap1 ldifgen groups --helpBuild several dataset shapes so you can separate many-small-group behavior from few-very-large-group behavior:
1,000 groups × 10 members
500 groups × 100 members
100 groups × 1,000 members
10 groups × 10,000 members
1 group × 100,000 membersGenerate a medium lab file with groupOfNames and member:
dsctl ldap1 ldifgen groups perf_group__ --number 100 --suffix "dc=example,dc=com" --parent "ou=Groups,dc=example,dc=com" --num-members 1000 --create-members --member-parent "ou=People,dc=example,dc=com" --member-attr member --ldif-file /tmp/large-groups.ldifSuccessfully created LDIF file: /tmp/large-groups.ldifFor groupOfUniqueNames, pass --member-attr uniquemember. Load with online ldapadd when you need plug-in and index behavior, or with dsctl ldap1 ldif2db for offline bulk-load testing on a disposable backend. Keep those results separate—online LDAP operations exercise the normal write path, including MemberOf processing and index maintenance, while offline import bypasses normal LDAP operation handling. Benchmark Referential Integrity separately with controlled delete, rename, and move operations.
nsslapd-maxbersize during online ldapadd. Check the generated LDIF entry size before testing. Prefer an offline import on a disposable backend when the entry cannot fit safely within the configured LDAP request limit.
See Benchmark performance with ldclt for full generator and load-path detail.
Configure safe membership indexes
List indexes on the backend that holds your groups:
Online configuration in this section uses dsconf commands.
dsconf ldap1 backend index list userroot...
dn: cn=member,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config
...
dn: cn=memberOf,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config
...
dn: cn=uniquemember,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config
...Inspect the membership attributes your application uses:
dsconf ldap1 backend index get --attr member userrootdn: cn=member,cn=index,cn=userroot,cn=ldbm database,cn=plugins,cn=config
cn: member
nsIndexType: eq
nsIndexType: presThe lab already has member, memberOf, and uniquemember index entries. Use two different paths depending on what you find.
When the index entry does not exist:
dsconf ldap1 backend index add --attr member --index-type eq --reindex userrootWhen the index entry exists but lacks equality indexing:
dsconf ldap1 backend index set --attr member --add-type eq --reindex userrootApply the same distinction to uniquemember and memberOf when applications filter on uniqueMember or memberOf.
Verify application filters in the access log before adding indexes. General index theory and reindex troubleshooting live in Configure LDAP indexes.
Do not create substring indexes on membership attributes
member: sub or uniqueMember: sub on large static groups. Directory Server must evaluate substring index keys for the complete multi-valued attribute when a member is added or removed. On groups with thousands of values, routine membership changes become significantly more expensive. Red Hat explicitly warns against substring indexes on member and uniqueMember.
Use equality searches instead:
(member=USER_DN)
(uniqueMember=USER_DN)When an application submits (member=*uid=user1*), correct the client filter rather than adding a substring index to support an inefficient partial-DN search.
If a substring index was added previously, remove it and rebuild:
dsconf ldap1 backend index set --attr member --del-type sub --reindex userrootdsconf ldap1 backend index set --attr uniquemember --del-type sub --reindex userrootAfter removal, repeat your group modification test, confirm search behavior, and monitor the access log for newly unindexed queries.
Benchmark group reads and modifications
Measure complete-group reads, indexed membership searches, reverse memberOf reads, and incremental modifications separately. The lab group cn=all-employees,ou=Groups,dc=example,dc=com contains 512 member values—a modest lab group useful for small-to-medium timing comparisons before you scale to the 5,000-member medium tier in generated datasets.
Retrieve the complete group
time ldapsearch -LLL -o ldif-wrap=no -Y EXTERNAL -H ldapi://%2Frun%2Fslapd-ldap1.socket -b "cn=all-employees,ou=Groups,dc=example,dc=com" -s base membermember: uid=user497,ou=people,dc=example,dc=com
member: uid=user498,ou=people,dc=example,dc=com
member: uid=user499,ou=people,dc=example,dc=com
member: uid=user500,ou=people,dc=example,dc=com
real 0m0.308sMeasure response size as well as latency:
ldapsearch -LLL -o ldif-wrap=no -Y EXTERNAL -H ldapi://%2Frun%2Fslapd-ldap1.socket -b "cn=all-employees,ou=Groups,dc=example,dc=com" -s base member | tee /tmp/all-employees.ldif | wc -c24864grep -c '^member:' /tmp/all-employees.ldif512Record membership count, returned bytes, client time, server etime from the access log or logconv.pl, and client memory use.
Search for groups containing one user
time ldapsearch -LLL -Y EXTERNAL -H ldapi://%2Frun%2Fslapd-ldap1.socket -b "ou=Groups,dc=example,dc=com" "(member=uid=user1,ou=people,dc=example,dc=com)" dndn: cn=developers,ou=Groups,dc=example,dc=com
dn: cn=all-employees,ou=Groups,dc=example,dc=com
dn: cn=full-time-employees,ou=Groups,dc=example,dc=com
real 0m0.017sThese two timings measure different operations: one transfers hundreds of values from a single entry; the other returns a few group DNs. An exact-DN equality search avoids transferring the complete membership list and allows the equality index to narrow candidate groups. Treat its timing separately from a base-object read that returns every member value.
For a true index comparison, run the same (member=USER_DN) search with the equality index present, after removing it on a disposable backend, and after restoring and rebuilding it—then compare access-log notes, etime, and entries examined.
Read reverse membership from the user
ldapsearch -LLL -Y EXTERNAL -H ldapi://%2Frun%2Fslapd-ldap1.socket -b "uid=user1,ou=people,dc=example,dc=com" -s base memberOfdn: uid=user1,ou=people,dc=example,dc=com
memberOf: cn=developers,ou=Groups,dc=example,dc=com
memberOf: cn=engineering,ou=Groups,dc=example,dc=com
memberOf: cn=all-employees,ou=Groups,dc=example,dc=com
memberOf: cn=full-time-employees,ou=Groups,dc=example,dc=comCompare the cost of retrieving a very large group entry versus reading one user's memberOf values. Request only attributes the application needs—a search that requests * can pull the complete membership list when the client only needs the group name.
Benchmark incremental modifications
Add one membership value with a single-value LDAP modification rather than replacing the entire member attribute. Compare a small-group control against the 512-member cn=all-employees group so modification cost is not measured only on a one-member entry.
Confirm each test user exists and is not already a member of the target group. Otherwise LDAP can return Type or value exists (20) instead of measuring a successful addition:
ldapsearch -LLL -Y EXTERNAL -H ldapi://%2Frun%2Fslapd-ldap1.socket -b "cn=developers,ou=Groups,dc=example,dc=com" -s base "(member=uid=user50001,ou=people,dc=example,dc=com)" dnAn empty result means the user is not yet a member. Use a group without overlapping Auto Membership rules when those rules would immediately recreate membership.
Small-group control (cn=developers, one member)
Create uid=user50001 with ldapadd when the entry does not already exist.
time ldapmodify -Y EXTERNAL -H ldapi://%2Frun%2Fslapd-ldap1.socket <<'EOF'
dn: cn=developers,ou=Groups,dc=example,dc=com
changetype: modify
add: member
member: uid=user50001,ou=people,dc=example,dc=com
EOFmodifying entry "cn=developers,ou=Groups,dc=example,dc=com"
real 0m0.028stime ldapmodify -Y EXTERNAL -H ldapi://%2Frun%2Fslapd-ldap1.socket <<'EOF'
dn: cn=developers,ou=Groups,dc=example,dc=com
changetype: modify
delete: member
member: uid=user50001,ou=people,dc=example,dc=com
EOFmodifying entry "cn=developers,ou=Groups,dc=example,dc=com"
real 0m0.027sLarge-group test (cn=all-employees, 512 members)
Pick a user who is not already a member. In this lab, uid=user501 is not in cn=all-employees:
ldapsearch -LLL -Y EXTERNAL -H ldapi://%2Frun%2Fslapd-ldap1.socket -b "cn=all-employees,ou=Groups,dc=example,dc=com" -s base "(member=uid=user501,ou=people,dc=example,dc=com)" dnAdd one membership value:
time ldapmodify -Y EXTERNAL -H ldapi://%2Frun%2Fslapd-ldap1.socket <<'EOF'
dn: cn=all-employees,ou=Groups,dc=example,dc=com
changetype: modify
add: member
member: uid=user501,ou=people,dc=example,dc=com
EOFmodifying entry "cn=all-employees,ou=Groups,dc=example,dc=com"
real 0m0.289sRemove the value afterward:
time ldapmodify -Y EXTERNAL -H ldapi://%2Frun%2Fslapd-ldap1.socket <<'EOF'
dn: cn=all-employees,ou=Groups,dc=example,dc=com
changetype: modify
delete: member
member: uid=user501,ou=people,dc=example,dc=com
EOFmodifying entry "cn=all-employees,ou=Groups,dc=example,dc=com"
real 0m0.277sIn this lab, the 512-member group modifications took about ten times longer than the one-member control. MemberOf and index maintenance were enabled during both runs; that configuration was associated with the higher latency on the large group, although a single timing pair does not isolate each component.
Capture client latency plus access-log wtime, optime, and etime through logconv.pl as described in Benchmark performance with ldclt. Compare incremental add and delete against a client that replaces the full member attribute. Run modifications with production-required plug-ins enabled.
Tune MemberOf and membership fixup tasks
The MemberOf plug-in updates reverse membership on user entries whenever static group membership changes. Review the active configuration:
dsconf ldap1 plugin memberof showmemberofattr: memberOf
memberofentryscope: dc=example,dc=com
memberofentryscopeexcludesubtree: ou=Private,dc=example,dc=com
memberofgroupattr: member
memberofgroupattr: uniqueMember
memberofskipnested: offApply related MemberOf configuration changes together, restart the instance once, and verify the resulting configuration. Run a targeted fixup when a change affects previously calculated memberOf values.
Limit entry scope and exclude archive branches:
dsconf ldap1 plugin memberof set --scope "dc=example,dc=com"dsconf ldap1 plugin memberof set --exclude "ou=Archive,dc=example,dc=com"Monitor only membership attributes in use:
dsconf ldap1 plugin memberof set --groupattr member uniqueMemberOn 389 DS 3.2, optionally limit processing to selected group object classes or filters with --specific-group-oc, --specific-group-filter, and --exclude-specific-group-filter. Do not configure conflicting include and exclude filters. Run a memberOf fixup after changing group-specific filtering so existing memberOf values match the new rules.
dsctl ldap1 restartdsconf ldap1 plugin memberof showComplete attribute reference and shared-configuration detail live in Configure the memberOf plug-in.
Validate nested-group schema before benchmarking
When a group is itself a member of another group, add extensibleObject to the nested child group entry so it can store the operational memberOf value from the parent. In the example below, cn=developers is nested inside cn=engineering, so cn=developers must permit memberOf:
dn: cn=developers,ou=Groups,dc=example,dc=com
objectClass: top
objectClass: groupOfNames
objectClass: extensibleObject
member: uid=user1,ou=People,dc=example,dc=com
memberOf: cn=engineering,ou=Groups,dc=example,dc=comWithout an object class that permits memberOf, updates can fail with LDAP result code 65, Object Class Violation. Red Hat confirms that groups used in nested membership require extensibleObject.
Confirm the live entry before benchmarking indirect membership:
ldapsearch -LLL \
-Y EXTERNAL \
-H ldapi://%2Frun%2Fslapd-ldap1.socket \
-b "cn=developers,ou=Groups,dc=example,dc=com" \
-s base \
objectClass member memberOfDisable nested expansion when indirect membership is unnecessary
When applications require only direct membership:
dsconf ldap1 plugin memberof set --skipnested onWithout skip-nested processing, Directory Server examines parent-group relationships to maintain direct and indirect memberOf values. For users already belonging to many groups, those repeated searches can consume substantial CPU.
| Requirement | --skipnested |
|---|---|
| Applications require indirect group membership | off |
| Only direct membership is required | on |
| No groups contain other groups | on is normally appropriate |
Restart, verify with dsconf ldap1 plugin memberof show, run fixup on a pilot subtree, and verify representative users and nested groups. Do not enable skip-nested processing only for speed when applications depend on indirect membership.
Avoid unnecessary cross-backend searches
Enable all-backend processing only when users and groups genuinely reside in different databases:
dsconf ldap1 plugin memberof set --allbackends onCross-backend processing broadens the searches required during each membership change. Keep frequently modified groups and their member users in the same backend where the directory design permits.
Run MemberOf fixup safely
Run fixup after enabling MemberOf on existing data, importing group or user LDIF, changing nested behavior, changing scope, or changing group-specific filters. Start with a narrow subtree and an explicit filter when user entries use inetOrgPerson:
dsconf ldap1 plugin memberof fixup -f "(objectClass=inetOrgPerson)" "ou=People,dc=example,dc=com"Adding fixup task entry...
Successfully added task entry "cn=memberOf_fixup_2026-07-18T06:04:09.334444,cn=memberOf task,cn=tasks,cn=config". This task is running in the background. To track its progress you can use the "fixup-status" command.Monitor progress:
dsconf ldap1 plugin memberof fixup-status --watchOr inspect the task log:
dsconf ldap1 plugin memberof fixup-status --show-logFound 1 fix-up task
- Base DN: ou=people,dc=example,dc=com
- Filter: (objectclass=inetorgperson)
- Status: Memberof task finished (processed 511 entries in 1 seconds)
- Exit Code: 0When -f is omitted, MemberOf fixup selects entries containing inetUser, inetAdmin, or nsMemberOf. Add an explicit filter when your users contain only another suitable object class such as inetOrgPerson. That default selection is documented by Red Hat and implemented by the current dsconf command.
Before a large fixup, record CPU and memory, check replication backlog, stop competing import or fixup tasks, pilot on a small subtree, schedule production work during reduced traffic, and verify a sample of users afterward.
The task is created and executed on the selected server. Whether its resulting memberOf changes replicate depends on your fractional-replication model. When memberOf is excluded from replication and every server calculates it locally, run the repair on each server that needs recalculation. When suppliers calculate memberOf and replicate it to read-only consumers, run the task on the appropriate calculating supplier and verify consumer convergence.
Control Auto Membership and Referential Integrity load
Large Auto Membership fixup tasks can update many static groups and trigger MemberOf processing. Run a targeted task asynchronously:
dsconf ldap1 plugin automember fixup "ou=People,dc=example,dc=com" -f "(objectClass=inetOrgPerson)" -s subAttempting to add task entry... This will fail if Automembership plug-in is not enabled.
Successfully added task entry "cn=automember_rebuild_2026-07-18T05:51:23.649897,cn=automember rebuild membership,cn=tasks,cn=config". This task is running in the background. To track its progress you can use the "fixup-status" command.Without --wait, dsconf submits the background task and returns; --timeout is not used for that submission response.
Check status immediately after submission:
dsconf ldap1 plugin automember fixup-statusFound 1 fix-up task
- Base DN: ou=people,dc=example,dc=com
- Filter: (objectClass=inetOrgPerson)
- Status: Automember rebuild task finished. Processed (0) entries in 0 secondsProcessed (0) means no entries matched the submitted base DN, filter, and configured Auto Membership definitions. If matches were expected, inspect the definition scope, definition filter, target groups, and the fixup filter you passed. Without matching definitions, the task can finish successfully while performing no membership updates.
Choose either asynchronous submission or synchronous waiting; do not run both for the same test. To block until completion instead of polling fixup-status, add --wait and set a client-side limit:
dsconf ldap1 plugin automember fixup \
"ou=People,dc=example,dc=com" \
-f "(objectClass=inetOrgPerson)" \
-s sub --wait \
--timeout 300--timeout limits how long the client waits for task completion when --wait is also set. It is not a server CPU or task-runtime limit, and a timed-out client does not necessarily mean the server-side task stopped.
Cancel when server load becomes unsafe:
dsconf ldap1 plugin automember abort-fixupUse Auto Membership dry-run tasks, limit base DN and filter, and avoid running multiple membership fixups simultaneously. Rule configuration lives in Auto Membership.
Referential Integrity searches configured DN-valued attributes after entry deletes, renames, and moves. For large groups, keep member and uniqueMember equality-indexed, limit container scope to branches that store references, and measure delete latency when one user belongs to hundreds of groups. Complete Referential Integrity configuration is in Referential Integrity.
Tune client queries and replication behavior
Prefer efficient query patterns:
| Goal | Prefer |
|---|---|
| Find groups for one user with MemberOf enabled | Base read of memberOf on the user entry |
| Find groups without MemberOf | (member=USER_DN) with equality index |
| Group metadata only | dn, cn, description — not * |
| Partial DN wildcard | Fix the client — not a substring index |
Avoid repeatedly reading the same huge group when application caching and your authorization model permit bounded staleness. A group entry with tens of thousands of values can also stress LDAP client libraries, application memory, JSON conversion, and proxy response limits—measure client and server behavior together.
In a replicated topology, test membership modifications through every writable supplier and keep one consistent MemberOf model:
Local calculation on every server:
Enable MemberOf on suppliers and consumers
Exclude memberOf from replication
Supplier calculation with consumer replication:
Enable MemberOf on writable suppliers
Exclude memberOf between writable suppliers
Replicate memberOf to read-only consumers
Disable MemberOf on those consumersAvoid changing tens of thousands of group values through different suppliers simultaneously.
Monitor large-group operations
Review access and error logs under /var/log/dirsrv/slapd-ldap1/. Correlate operations by conn and op, and capture wtime, optime, etime, notes, result code, and entries returned. Use logconv.pl on rotated access logs as described in Benchmark performance with ldclt.
Check Directory Server counters:
dsconf ldap1 monitor serverversion: 389-Directory/3.2.0 B2026.177.0000
threads: 18
currentconnections: 1
opsinitiated: 4658
opscompleted: 4657
entriessent: 3328Track complete group reads, equality membership searches, incremental adds and deletes, MemberOf-generated writes, fixup tasks, and replication updates separately.
Before-and-after test matrix
Populate this worksheet during testing on your own dataset:
| Test | Small group | Large group | Tuned result |
|---|---|---|---|
| Read complete group | |||
Search (member=USER_DN) |
|||
| Add one member | |||
| Delete one member | |||
| Replace all members | |||
Read user memberOf |
|||
| Nested membership change | |||
| MemberOf fixup | |||
| Delete referenced user | |||
| Replication convergence |
Change one tuning lever per comparison run—for example baseline, remove a substring membership index and retest, or enable --skipnested and retest. Do not change indexes, plug-in scope, cache sizes, and replication settings in a single comparison.
After testing, remove generated users and groups, delete temporary LDIF exports, and restore any plug-in settings you changed (memberofskipnested, scope, all-backends, or specific-group filters) followed by a targeted fixup.
Troubleshoot large-group performance
| Symptom | Likely cause | Fix |
|---|---|---|
| Adding one member is unexpectedly slow | Substring index on member or uniqueMember, nested MemberOf, many parent groups, Referential Integrity, replication backlog |
Remove substring indexes; narrow MemberOf scope; measure plug-in and replication cost per change |
| Group search is slow despite equality index | Wrong filter, incomplete reindex, ID-list scan limits, broad search base | Match client filter to indexed equality form; check access-log notes=A or notes=U |
| Reading the group consumes excessive memory | Client requests full membership list | Request fewer attributes; read memberOf on the user when MemberOf is enabled |
| MemberOf updates use high CPU | Nested expansion, broad scope, all-backends search, overly broad group filters | Tune memberofskipnested, scope, exclude subtrees, and group-specific filters |
| Fixup task affects normal traffic | Wide base DN, competing import or fixup tasks | Narrow base and filter; schedule during reduced load |
| Auto Membership fixup overloads the server | Complex rules on large groups with MemberOf enabled | Check fixup-status; run abort-fixup; pilot with dry-run tasks |
| Deleted user causes long delays | Referential Integrity scope or missing equality indexes | Limit scope; index maintained DN attributes |
| Membership differs across replicas | Inconsistent plug-in placement or fractional replication | Align MemberOf model; check backlog and supplier used for updates |
| Application sees stale nested membership | memberofskipnested=on while indirect membership is required |
Disable skip-nested; run fixup; retest authorization |
User memberOf missing after group change |
MemberOf disabled, wrong group attribute, scope mismatch, fixup not run | Confirm plug-in state and scopes; run targeted fixup |
Type or value exists (20) during benchmark add |
Member already present or Auto Membership recreated membership | Verify with a base-scope filter before add; choose a test group without overlapping rules |
What's next
After you complete this guide, continue with:
- Tune LMDB, Entry Cache and DN Cache in 389 Directory Server — memory and map-size planning
- Configure LDAP Search Limits in 389 Directory Server — unindexed search controls
- Benchmark 389 Directory Server Performance with ldclt and logconv — repeatable load measurement
Summary
- Inventory the largest static groups with an LDIF-aware membership count.
- Build reproducible test datasets with
dsctl ldifgen groupson a disposable backend. - Configure equality indexes for
member,uniqueMember, andmemberOfwhere filters require them. - Never add substring indexes to membership attributes on large groups.
- Measure complete-group reads, indexed searches, and incremental modifications separately.
- Narrow MemberOf scope, group attributes, and group-specific filters; enable skip-nested only when indirect membership is unnecessary.
- Run MemberOf and Auto Membership fixups on pilot subtrees during controlled activity.
- Account for Referential Integrity, replication, and client result handling—not only local database latency.
References
- Red Hat Directory Server 13 — User management and authentication
- Red Hat Directory Server 13 — Managing indexes in Directory Server
- 389 Directory Server — MemberOf plug-in scalability
- 389 Directory Server — MemberOf specific-group scoping
- 389 Directory Server — Database and LDIF generator design

