When many clients connect at once, worker threads, listener threads, and file descriptors determine whether operations queue or fail. This guide covers thread and connection tuning in 389 Directory Server.
Before you start:
- Install 389 Directory Server — running instance (
ldap1ondc=example,dc=comin this lab) - dsconf commands — online configuration
- Configure LDAP Search Limits in 389 Directory Server — size and time caps that protect workers from expensive searches
nsslapd-threadnumber, nsslapd-numlisteners, nsslapd-maxthreadsperconn, idle and I/O timeouts, and file descriptors. It does not configure search limits, LMDB cache, or host-level TCP stack tuning.
Tested on: Rocky Linux 10.2; 389 Directory Server 3.2.0.
Understand worker and connection resources
| Thread or limit | Attribute | Purpose |
|---|---|---|
| Worker threads | nsslapd-threadnumber |
Execute LDAP operations (-1 = auto-tune from CPU count; takes effect at startup after restart) |
| Listener threads | nsslapd-numlisteners |
Monitor established client connections (valid range 1–4; restart required) |
| Per-connection workers | nsslapd-maxthreadsperconn |
Cap simultaneous asynchronous operations from one connection (1 through active worker count) |
| Idle timeout | nsslapd-idletimeout / nsIdleTimeout |
Close unused connections after N seconds (0 disables automatic idle disconnect) |
| I/O block timeout | nsslapd-ioblocktimeout |
Milliseconds to wait on blocked network I/O (lab default 10000 = 10 seconds) |
| File descriptors | nsslapd-maxdescriptors / nsslapd-reservedescriptors |
Total descriptor ceiling and reserved pool for non-client use |
| Socket backlog | nsslapd-listen-backlog-size |
Pending socket queue for incoming connections during bursts |
nsslapd-numlisteners configures threads that monitor established client connections. nsslapd-listen-backlog-size controls the pending socket queue for incoming connections. Backlog tuning does not increase the number of threads monitoring established connections.
Increasing worker threads cannot fix unindexed searches, slow storage, lock contention, or client-side delays. Too many threads can add scheduling overhead without raising throughput.
Check current thread and connection settings
dsconf ldap1 config get nsslapd-threadnumber nsslapd-numlisteners nsslapd-maxthreadsperconn nsslapd-maxdescriptors nsslapd-reservedescriptors nsslapd-listen-backlog-size nsslapd-idletimeout nsslapd-ioblocktimeoutnsslapd-threadnumber: 16
nsslapd-numlisteners: 1
nsslapd-maxthreadsperconn: 5
nsslapd-maxdescriptors: 524288
nsslapd-reservedescriptors: 65
nsslapd-listen-backlog-size: 128
nsslapd-idletimeout: 3600
nsslapd-ioblocktimeout: 10000The lab baseline is sixteen worker threads, one listener, five operations per connection, and 524288 max descriptors with 65 reserved.
The configured descriptor allowance for TCP clients is approximately nsslapd-maxdescriptors minus nsslapd-reservedescriptors, which is 524223 in this lab. This is not a guaranteed simultaneous-client count. The live dtablesize monitor value reports the Directory Server connection-table size; in this lab it is 63936, which is a lower practical connection-slot boundary. Monitor dtablesize, currentconnections, the operating-system descriptor limit, and the error log together. Changes to either descriptor setting require a restart.
Tune worker threads
Prefer automatic tuning unless repeatable load tests justify a fixed count:
dsconf ldap1 config replace nsslapd-threadnumber=-1Successfully replaced value(s) for 'nsslapd-threadnumber': '-1'nsslapd-threadnumber defines the worker threads created at startup. Restart so auto-tuning takes effect:
dsctl ldap1 restartRead the attribute after restart:
dsconf ldap1 config get nsslapd-threadnumbernsslapd-threadnumber: 16Setting -1 enables auto-tuning, but config get displays the calculated active thread count. On this lab host, which falls in the 1–16 CPU range, the value is 16. That displayed number does not mean the configuration has become a fixed manual value.
Automatic behaviour on current RHDS guidance:
1–16 CPU threads:
16 Directory Server worker threads
17–512 CPU threads:
One worker per CPU thread
More than 512 CPU threads:
Maximum 512 worker threadsReturn to a fixed pool only when measurement requires it. The fixed value takes effect after restart:
dsconf ldap1 config replace nsslapd-threadnumber=16dsctl ldap1 restartAuto-tuning should remain the normal recommended end state unless repeatable load testing justifies a fixed value.
Tune listener threads and per-connection limits
Connection listener threads
dsconf ldap1 config get nsslapd-numlistenersnsslapd-numlisteners: 1The documented default is 1 and the valid range is 1 through 4. Increase listener threads only when testing with many established connections shows that one listener cannot service connection activity efficiently:
dsconf ldap1 config replace nsslapd-numlisteners=4Restart after changing listener count:
dsctl ldap1 restartPending connection bursts during accept are controlled separately by nsslapd-listen-backlog-size, not by adding listener threads.
Per-connection worker limit
dsconf ldap1 config get nsslapd-maxthreadsperconnnsslapd-maxthreadsperconn: 5This limit matters when one LDAP connection submits several asynchronous operations. Search the access log for per-connection pressure before raising the cap:
grep -E 'notes=.*(N|B)' /var/log/dirsrv/slapd-ldap1/accessconn=66 op=973 RESULT err=0 tag=101 nentries=2 etime=0.000571769 notes=N details="Not synchronous operation"notes=N identifies asynchronous operations that may consume multiple workers. notes=B identifies an operation that is delaying other incoming operations on the same connection.
Raise the limit only when monitoring supports it. The valid range is 1 through the active worker-thread count:
dsconf ldap1 config replace nsslapd-maxthreadsperconn=10Successfully replaced value(s) for 'nsslapd-maxthreadsperconn': '10'Verify the change:
dsconf ldap1 config get nsslapd-maxthreadsperconnnsslapd-maxthreadsperconn: 10Monitor while the application exercises concurrent operations on one connection:
dsconf ldap1 monitor serverWatch maxthreadsperconnhits and currentconnectionsatmaxthreads during the test. Increasing this value reallocates more of the global worker pool to a single connection. It can help a legitimate asynchronous client but can also let one connection consume a disproportionate number of workers.
Restore the lab baseline after testing:
dsconf ldap1 config replace nsslapd-maxthreadsperconn=5Do not raise nsslapd-maxthreadsperconn merely because an application opens many separate connections.
Configure idle, I/O, and connection limits
Global idle timeout
Close idle connections after ten minutes:
dsconf ldap1 config replace nsslapd-idletimeout=600Successfully replaced value(s) for 'nsslapd-idletimeout': '600'nsslapd-idletimeout: 0 disables automatic idle disconnection. A value that is too low can interrupt long-lived application pools and replication initialization.
Per-user idle timeout
Service or replication accounts can carry a longer idle timeout without weakening the global policy. With the global value at 600 seconds above, grant reporting-app thirty minutes. Save application-idle-timeout.ldif:
dn: uid=reporting-app,ou=ServiceAccounts,dc=example,dc=com
changetype: modify
replace: nsIdleTimeout
nsIdleTimeout: 1800ldapmodify -x -H ldap://ldap1.example.com:389 -D "cn=Directory Manager" -W -f application-idle-timeout.ldifmodifying entry "uid=reporting-app,ou=ServiceAccounts,dc=example,dc=com"ldapsearch -x -H ldap://ldap1.example.com:389 \
-D "cn=Directory Manager" -W \
-b "uid=reporting-app,ou=ServiceAccounts,dc=example,dc=com" \
-s base "(objectClass=*)" nsIdleTimeoutnsIdleTimeout: 1800Per-user nsIdleTimeout overrides nsslapd-idletimeout for that bind DN. Selected accounts can also receive a tighter timeout when a stricter per-application limit is required.
Blocked I/O timeout
nsslapd-ioblocktimeout closes a connection when the client makes no progress during a read or write. The lab default 10000 is ten seconds. Raising the value allows slow clients longer to recover, but also retains blocked connections and their descriptors for longer.
dsconf ldap1 config replace nsslapd-ioblocktimeout=180000Successfully replaced value(s) for 'nsslapd-ioblocktimeout': '180000'180000 milliseconds is 180 seconds. Use such a high value only when legitimate slow clients are being disconnected by the default ten-second timeout. Confirm the unit and supported range in the configuration reference for the installed release before selecting a production value.
File descriptors
dsconf ldap1 config get nsslapd-maxdescriptors nsslapd-reservedescriptorsCheck the systemd unit limit before raising Directory Server descriptors:
systemctl show dirsrv@ldap1 -p LimitNOFILELimitNOFILE=524288The service limit matches nsslapd-maxdescriptors: 524288 on the lab host. nsslapd-reservedescriptors protects descriptors needed for indexes, databases, logs, replication, chaining, and other non-client activity. Do not set nsslapd-maxdescriptors above the operating-system limit.
Socket backlog
dsconf ldap1 config replace nsslapd-listen-backlog-size=256Use backlog tuning only when connection bursts fill the pending socket queue. It does not add listener threads for established connections.
Monitor connections, threads, and queued operations
dsconf ldap1 monitor serverSample output (trimmed):
threads: 18
currentconnections: 1
totalconnections: 2
currentconnectionsatmaxthreads: 0
maxthreadsperconnhits: 0
dtablesize: 63936
readwaiters: 0
opsinitiated: 12
opscompleted: 11currentconnections is the open connection count right now. maxthreadsperconnhits shows how often clients exceeded nsslapd-maxthreadsperconn. dtablesize reports the connection-table size. The supported operation counters are opsinitiated and opscompleted.
threads reports the current number of active request-handling threads. Red Hat documents that internal tasks such as replication can create additional threads beyond the nsslapd-threadnumber pool. On this lab host config get shows 16 configured workers while monitor reports threads: 18. Use nsslapd-threadnumber for the startup worker pool and threads for the live count.
Also read the monitor LDAP entry:
ldapsearch -x -H ldap://ldap1.example.com:389 \
-D "cn=Directory Manager" -W \
-b "cn=monitor" -s base "(objectClass=*)" \
currentconnections totalconnections \
currentconnectionsatmaxthreads maxthreadsperconnhits \
dtablesize readwaiters threads opsinitiated opscompletedcurrentconnections: 1
totalconnections: 3
currentconnectionsatmaxthreads: 0
maxthreadsperconnhits: 0
dtablesize: 63936
readwaiters: 0
threads: 18
opsinitiated: 15
opscompleted: 14Watch these signals after thread or connection changes:
currentconnectionsapproaching the usable client-descriptor capacity, whiledtablesizeand the error log indicate low descriptor headroomcurrentconnectionsatmaxthreadsremaining above zeromaxthreadsperconnhitsincreasing on LDAP connection poolsreadwaitersrising because of slow clients or networks- Access-log
wtimeincreasing because operations are waiting in the work queue
Red Hat defines wtime as the period an operation waits in the work queue before a worker thread accepts it. When the server runs out of descriptors, the error log can report Not listening for new connections -- too many fds open.
dsconf ldap1 monitor ldbm complements server-wide monitoring when database load shifts after connection tuning.
Restore lab baseline after testing
The examples above change production-impacting values. Restore the lab defaults and restart when tuning exercises finish:
dsconf ldap1 config replace nsslapd-threadnumber=-1
dsconf ldap1 config replace nsslapd-numlisteners=1
dsconf ldap1 config replace nsslapd-maxthreadsperconn=5
dsconf ldap1 config replace nsslapd-idletimeout=3600
dsconf ldap1 config replace nsslapd-ioblocktimeout=10000
dsconf ldap1 config replace nsslapd-listen-backlog-size=128dsctl ldap1 restartRemove the per-user idle override when the exercise used application-idle-timeout.ldif. Save remove-application-idle-timeout.ldif:
dn: uid=reporting-app,ou=ServiceAccounts,dc=example,dc=com
changetype: modify
delete: nsIdleTimeoutldapmodify -x -H ldap://ldap1.example.com:389 -D "cn=Directory Manager" -W -f remove-application-idle-timeout.ldifmodifying entry "uid=reporting-app,ou=ServiceAccounts,dc=example,dc=com"Verify the restored configuration:
dsconf ldap1 config get nsslapd-threadnumber nsslapd-numlisteners nsslapd-maxthreadsperconn nsslapd-idletimeout nsslapd-ioblocktimeout nsslapd-listen-backlog-sizensslapd-threadnumber: 16
nsslapd-numlisteners: 1
nsslapd-maxthreadsperconn: 5
nsslapd-idletimeout: 3600
nsslapd-ioblocktimeout: 10000
nsslapd-listen-backlog-size: 128After restart with nsslapd-threadnumber=-1, config get may still display the calculated thread count such as 16. That is expected auto-tuning behaviour, not a fixed manual setting.
Troubleshoot thread and connection problems
| Symptom | Likely cause | Fix |
|---|---|---|
maxthreadsperconnhits climbing |
Too many concurrent ops per connection | Raise nsslapd-maxthreadsperconn within the worker count or spread load across connections |
notes=N or notes=B in access logs |
Asynchronous or blocking operations on one connection | Review client behaviour before raising per-connection limits |
| Connections dropped after idle periods | nsslapd-idletimeout or load-balancer timeout |
Align server, firewall, and client pool keepalive settings; consider per-user nsIdleTimeout |
| Bind failures under load | Descriptor limit mismatch | Align nsslapd-maxdescriptors with LimitNOFILE; check usable capacity minus reserved descriptors |
Not listening for new connections -- too many fds open |
Descriptor exhaustion | Review dtablesize, currentconnections, and reserved descriptors |
Thread count unchanged after -1 |
Auto-tune displays calculated value | Read monitor server threads and CPU count |
| Increasing threads does not help | Bottleneck is indexing, I/O, or locks | Restore automatic tuning; fix search and storage problems first |
What's next
After you complete this guide, continue with:
- Tune LMDB, Entry Cache and DN Cache in 389 Directory Server — LMDB cache and reader settings
- Benchmark 389 Directory Server Performance with ldclt and logconv — baseline before changing thread counts
- Configure 389 Directory Server Indexes for Faster LDAP Searches — index coverage for concurrent searches
- Configure Low Disk Space Protection in 389 Directory Server — I/O pressure under load
Summary
- Prefer
nsslapd-threadnumber=-1unless load tests justify a fixed count after restart. - Listener threads default to
1; raisensslapd-numlistenersonly when many established connections show response-time degradation. - Usable client descriptor capacity is approximately
nsslapd-maxdescriptorsminusnsslapd-reservedescriptors. - Monitor
currentconnectionsatmaxthreads,maxthreadsperconnhits,readwaiters,dtablesize, and access-logwtimeafter every change. - Fix expensive searches through search limits and indexes before adding workers.
References
- Red Hat Directory Server 13 — Performance tuning (§9.3 thread auto-tuning)
- Red Hat Directory Server 13 — Monitoring server and database activity
- Red Hat Directory Server 13 — Log files reference (
wtime,notes=N,notes=B) - Red Hat Directory Server 13 — Configuration and schema reference

