Tested on: Rocky Linux 10.2; OpenLDAP 2.6.10; suffix
dc=example,dc=com; StartTLS required for simple binds;LDAPTLS_CACERT=/etc/openldap/certs/example-ldap-ca.crt.
ldapsearch — quick reference
Search scope and output
Choose the narrowest base DN and scope that answer the question. -LLL strips LDIF comments and the version line so scripts get predictable records.
| When to use | Command |
|---|---|
| Read the Root DSE without credentials | ldapsearch -x -LLL -H ldap://localhost -s base -b "" namingContexts |
Search the whole suffix (default sub scope) |
ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "dc=example,dc=com" "(objectClass=*)" |
| Search every descendant explicitly | ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "dc=example,dc=com" -s sub "(uid=*)" |
| Read one entry only | ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "dc=example,dc=com" -s base "(objectClass=*)" |
| Search immediate children of an OU | ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "ou=people,dc=example,dc=com" -s one "(uid=*)" |
| Return selected attributes only | ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "ou=people,dc=example,dc=com" "(uid=alice)" cn mail |
| Suppress attribute values (names only) | ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "uid=alice,ou=people,dc=example,dc=com" -s base -A "(objectClass=*)" |
| Request operational attributes | ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "uid=alice,ou=people,dc=example,dc=com" -s base "(objectClass=*)" + |
| Return no attributes (DN list only) | ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "ou=people,dc=example,dc=com" "(uid=*)" dn |
LDAP filters (RFC 4515)
Filters are the third positional argument. Quote them so the shell does not treat parentheses as subshell syntax.
| When to use | Filter |
|---|---|
| Match every entry under the base | (objectClass=*) |
| Exact attribute match | (uid=alice) |
Prefix wildcard on cn |
(cn=A*) |
| Combine conditions (AND) | (&(objectClass=inetOrgPerson)(uid=alice)) |
| Match any of several values (OR) | `( |
| Negate a condition (NOT) | (!(uid=alice)) |
| Presence test (attribute exists) | (mail=*) |
| Approximate match (if server supports it) | (cn~=alice) |
Limits and paging
Client-side limits stop runaway result sets before they flood the terminal. Paged results walk large directories in server-defined chunks.
| When to use | Command |
|---|---|
| Cap how many entries the client accepts | ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "ou=people,dc=example,dc=com" -z 5 "(uid=*)" dn |
| Request one page of results | ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "ou=people,dc=example,dc=com" -E pr=100/noprompt "(uid=*)" dn |
| Set a server-side time limit (seconds) | ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "dc=example,dc=com" -l 10 "(objectClass=*)" |
Connection and TLS
On the tested host, olcSecurity: simple_bind=128 requires TLS before a password bind. Set LDAPTLS_CACERT or use -o TLS_CACERT=… so StartTLS can verify the server certificate.
| When to use | Command |
|---|---|
| Anonymous search over plain LDAP (Root DSE only on this server) | ldapsearch -x -LLL -H ldap://localhost -s base -b "" namingContexts |
| Require StartTLS for a simple bind | ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "dc=example,dc=com" "(objectClass=*)" |
| Request StartTLS but allow fallback | ldapsearch -x -Z -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "dc=example,dc=com" "(objectClass=*)" |
| Connect with LDAPS instead of StartTLS | ldapsearch -x -H ldaps://localhost -D "cn=admin,dc=example,dc=com" -W -b "dc=example,dc=com" "(objectClass=*)" |
| Point the client at a specific CA file | LDAPTLS_CACERT=/etc/openldap/certs/example-ldap-ca.crt ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "dc=example,dc=com" "(objectClass=*)" |
| Read dynamic server configuration as local root | sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b "cn=config" "(objectClass=olcDatabaseConfig)" |
Authenticated searches
Use StartTLS for simple binds on this server. The local LDAPI socket is the clean way to inspect cn=config.
| When to use | Command |
|---|---|
| Bind as the directory administrator over StartTLS | ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "dc=example,dc=com" "(objectClass=*)" |
| Supply a lab password non-interactively | ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -w 'PASSWORD' -b "dc=example,dc=com" "(objectClass=*)" |
| Read the password from a protected file | ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -y /root/ldap.pass -b "dc=example,dc=com" "(objectClass=*)" |
Debugging and dry-run
| When to use | Command |
|---|---|
| Print the LDAP operations without sending them | ldapsearch -n -v -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "ou=people,dc=example,dc=com" "(uid=alice)" cn |
| Raise the LDAP library debug level | ldapsearch -d 1 -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "ou=people,dc=example,dc=com" "(uid=alice)" cn |
| Show verbose connection and search details | ldapsearch -v -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "ou=people,dc=example,dc=com" "(uid=alice)" cn |
Help
| When to use | Command |
|---|---|
| Show the installed option inventory | ldapsearch -h |
| Print the OpenLDAP client version | ldapsearch -VV |
ldapsearch — command syntax
Synopsis from ldapsearch -h on the tested host:
usage: ldapsearch [options] [filter [attributes...]]
where:
filter RFC 4515 compliant LDAP search filter
attributes whitespace-separated list of attribute descriptions
which may include:
1.1 no attributes
* all user attributes
+ all operational attributesPositional arguments after the options:
- Filter — RFC 4515 string in parentheses. Omit it only when you pass
-f filterfile. - Attributes — zero or more attribute names. If you omit them, the server returns every attribute your identity may read.
Common filter shapes (shell quoting shown):
(uid=alice) equality
(cn=A*) substring (prefix)
(&(objectClass=inetOrgPerson)(mail=*)) AND — both must match
(|(uid=alice)(uid=bob)) OR — either matches
(!(uid=alice)) NOT — exclude matchesScope is controlled with -s:
| Flag | Name | Reads |
|---|---|---|
-s base |
baseObject | The base DN only |
-s one |
oneLevel | Direct children of the base |
-s sub |
subtree | Base and all descendants (default) |
For server setup and suffix details, see installing OpenLDAP on RHEL. User DNs and attributes are covered in managing OpenLDAP users and groups. Filter access is decided by OpenLDAP ACL examples.
ldapsearch — command examples
Essential Read the Root DSE anonymously
Start with the Root DSE when you do not yet know the naming context. It is a base-scope search at the empty DN and does not need a bind on most servers.
ldapsearch -x -LLL -H ldap://localhost -s base -b "" namingContextsSample output:
dn:
namingContexts: dc=example,dc=comThe namingContexts value is the suffix to use as the next search base. ACLs on the tested host still block anonymous reads under that suffix.
Essential Find a person and request only needed attributes
Search the people container by uid instead of dumping the entire directory. This server requires StartTLS and an authorized bind to read ou=people.
ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "ou=people,dc=example,dc=com" -LLL "(uid=alice)" cn mailSample output:
Enter LDAP Password:
dn: uid=alice,ou=people,dc=example,dc=com
cn: Alice Example
mail: [email protected]An absent result with exit status zero means the filter matched no readable entry.
Essential Combine filters with AND and OR
RFC 4515 prefix operators nest inside the filter string. AND narrows the result set; OR widens it.
AND requires every condition to match:
ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "ou=people,dc=example,dc=com" -LLL "(&(objectClass=inetOrgPerson)(uid=alice))" cn mailSample output:
Enter LDAP Password:
dn: uid=alice,ou=people,dc=example,dc=com
cn: Alice Example
mail: [email protected]OR returns entries that match any branch:
ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "ou=people,dc=example,dc=com" -LLL "(|(uid=alice)(uid=bob))" uid cnSample output:
Enter LDAP Password:
dn: uid=bob,ou=people,dc=example,dc=com
cn: Bob Example
uid: bob
dn: uid=alice,ou=people,dc=example,dc=com
cn: Alice Example
uid: aliceOrder of entries in the output is server-defined, not filter order.
Common Search with a substring (wildcard) filter
The asterisk is the RFC 4515 substring wildcard. Combine it with uid when you need a unique match in a busy OU.
ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "ou=people,dc=example,dc=com" -LLL "(&(cn=A*)(uid=alice))" cn uidSample output:
Enter LDAP Password:
dn: uid=alice,ou=people,dc=example,dc=com
cn: Alice Example
uid: aliceBroad (cn=A*) alone can return many entries; tighten the filter before scripting exports.
Essential List only direct people entries
Use -s one when you need immediate children, not nested groups or sub-OUs.
ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "ou=people,dc=example,dc=com" -s one -LLL "(|(uid=alice)(uid=bob))" dnSample output:
Enter LDAP Password:
dn: uid=bob,ou=people,dc=example,dc=com
dn: uid=alice,ou=people,dc=example,dc=comThe scope prevents a broad subtree scan as the directory grows.
Common Cap results with the client size limit
-z sets the maximum number of entries ldapsearch accepts. When more entries match, the client prints Size limit exceeded after the last allowed row.
ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "ou=people,dc=example,dc=com" -LLL -z 1 "(uid=*)" dnSample output:
Enter LDAP Password:
dn: uid=bob,ou=people,dc=example,dc=com
Size limit exceeded (4)Exit code 4 means the limit was hit — not necessarily an error if you only needed a sample.
Common List attribute names without values (-A)
-A is useful when you want a schema sketch of one entry without dumping sensitive values such as userPassword.
ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "uid=alice,ou=people,dc=example,dc=com" -s base -LLL -A "(objectClass=*)"Sample output:
Enter LDAP Password:
dn: uid=alice,ou=people,dc=example,dc=com
objectClass:
cn:
sn:
uid:
uidNumber:
gidNumber:
homeDirectory:
loginShell:
mail:
userPassword:Each line ending with a colon is an attribute name; no value follows.
Common Read operational metadata with +
Append + to the attribute list to request operational fields such as entryUUID, createTimestamp, and modifiersName.
ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "uid=alice,ou=people,dc=example,dc=com" -s base -LLL "(objectClass=*)" +Sample output:
Enter LDAP Password:
dn: uid=alice,ou=people,dc=example,dc=com
structuralObjectClass: inetOrgPerson
entryUUID: c6051d40-13a0-1041-9e47-ef9d6678656f
creatorsName: cn=admin,dc=example,dc=com
createTimestamp: 20260714072419Z
entryCSN: 20260714072419.911164Z#000000#000#000000
modifiersName: cn=admin,dc=example,dc=com
modifyTimestamp: 20260714072419Z
entryDN: uid=alice,ou=people,dc=example,dc=com
subschemaSubentry: cn=Subschema
hasSubordinates: FALSEOperational attributes are not returned unless you ask for them or use +.
Advanced Walk a large OU with paged results
-E pr=size/noprompt enables LDAP paged results so the client fetches the OU in chunks. /noprompt avoids waiting for interactive continuation between pages.
ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "ou=people,dc=example,dc=com" -LLL -E pr=1/noprompt "(|(uid=alice)(uid=bob))" dnSample output:
Enter LDAP Password:
dn: uid=alice,ou=people,dc=example,dc=com
# pagedresults: cookie=EwAAAAAAAAA=
dn: uid=bob,ou=people,dc=example,dc=com
# pagedresults: cookie=The # pagedresults: comment lines show the paging cookie between chunks.
Common Search with an administrator bind over StartTLS
This server requires TLS for simple binds. -W avoids placing the password in shell history; configure the certificate first with this OpenLDAP TLS guide.
ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "dc=example,dc=com" -LLL "(objectClass=organizationalUnit)" ouSample output:
Enter LDAP Password:
dn: ou=people,dc=example,dc=com
ou: people
dn: ou=groups,dc=example,dc=com
ou: groups
dn: ou=service-accounts,dc=example,dc=com
ou: service-accounts-ZZ makes a failed StartTLS negotiation an error instead of continuing unencrypted.
Common See the confidentiality error without StartTLS
When olcSecurity requires TLS for simple binds, a cleartext password bind fails before any search runs.
ldapsearch -x -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "dc=example,dc=com" -s base "(objectClass=*)"Sample output:
Enter LDAP Password:
ldap_bind: Confidentiality required (13)
additional info: confidentiality requiredAdd -ZZ (or use ldaps://) and a trusted CA before retrying.
Common Rehearse a search with -n (no operation)
-n asks the client to build the request without sending it — useful when you are validating URI, bind DN, filter quoting, and attribute lists.
ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "ou=people,dc=example,dc=com" -LLL -n "(uid=alice)" cnThe command exits silently with status zero and prints no LDIF. Pair -n with -v when you want a transcript of what would have been sent.
Common Read exactly one base entry
Use base scope to inspect the suffix object without listing descendants.
ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "dc=example,dc=com" -s base -LLL "(objectClass=*)" dc objectClassSample output:
Enter LDAP Password:
dn: dc=example,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
dc: exampleThis is a quick check that the suffix itself exists and is readable to your bind DN.
Advanced Inspect cn=config through LDAPI EXTERNAL
On the LDAP host, the Unix socket can authenticate the local root identity with SASL EXTERNAL. Run it through sudo rather than exposing a config password.
sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b "cn=config" "(objectClass=olcDatabaseConfig)" olcSuffixSample output:
dn: olcDatabase={2}mdb,cn=config
olcSuffix: dc=example,dc=comThis confirms which dynamic database serves the suffix.
ldapsearch — when to use / when not
| Use ldapsearch when | Use something else when |
|---|---|
|
|
ldapsearch vs ldapmodify
| ldapsearch | ldapmodify | |
|---|---|---|
| Operation | Reads entries | Changes existing entries or adds with -a |
| Input | Filter and requested attributes | LDIF change records |
| Risk | Read-only | Can alter directory data |
Related commands
These client tools cover the normal OpenLDAP administration flow.
| Command | One line |
|---|---|
| ldapsearch | Search and inspect directory entries. |
| ldapadd | Add entries from LDIF. |
| ldapmodify | Change attributes with LDIF. |
| ldapdelete | Remove entries by DN. |
| ldapwhoami | Confirm the authenticated identity. |
| slappasswd | Generate password hashes for OpenLDAP. |
Browse Linux commands for more command references.
ldapsearch — interview corner
Practice these before exams or standups. Each card explains the idea in plain language, then ends with a short answer you can say aloud.
What is the difference between base, one, and sub scope?
LDAP scope controls how far from the base DN the server walks the directory tree.
| Scope | Flag | What it returns |
|---|---|---|
| baseObject | -s base |
Only the base entry itself |
| oneLevel | -s one |
Direct children of the base |
| subtree | -s sub |
Base plus every descendant (default) |
Start narrow. A subtree search under dc=example,dc=com with (objectClass=*) can return the entire DIT and stress both the server and your terminal. Use base to verify one known DN, one to list immediate OUs or users, and reserve sub for when you genuinely need descendants.
A strong answer is:
"Base reads the base DN only, one reads its direct children, and sub reads the whole subtree. I pick the narrowest scope that still answers the question."
Why use ldapsearch -LLL?
By default, ldapsearch wraps results in LDIF scaffolding: a version line, a comment block describing base/scope/filter, and # comment lines before each entry. Each -L removes one layer of that decoration.
| Flags | Effect |
|---|---|
-L |
Omit the version line |
-LL |
Also omit the search banner comments |
-LLL |
Also omit per-entry comment lines |
-LLL does not change which entries match — only how they are formatted. Scripts that parse DN and attribute lines prefer -LLL because the output is stable and easy to pipe into awk or grep.
A strong answer is:
"Triple L strips LDIF comments and headers so I get clean records for terminals and scripts. It does not change the server's filter evaluation."
What does -ZZ do, and when is it required?
-Z requests StartTLS after connecting on plain ldap://. -ZZ does the same but treats a TLS failure as fatal instead of falling back to cleartext.
On servers with olcSecurity: simple_bind=128, password binds over unencrypted LDAP are rejected with ldap_bind: Confidentiality required (13) — you will see that before any search runs. That is why administrative examples pair -x -ZZ -H ldap://… -D … -W.
Also trust the server certificate: set LDAPTLS_CACERT or pass -o TLS_CACERT=…. Without a trusted CA, StartTLS can fail hostname or chain validation even when the server is correct.
A strong answer is:
"ZZ upgrades the connection with StartTLS and fails closed if TLS cannot be established. I use it whenever the server requires confidentiality for simple binds."
How do LDAP search filters work?
Filters use RFC 4515 syntax — always wrapped in parentheses. The most common operators:
| Operator | Example | Meaning |
|---|---|---|
| Equality | (uid=alice) |
Attribute equals value |
| Substring | (cn=A*) |
Prefix match |
| AND | (&(a=1)(b=2)) |
Both conditions |
| OR | `( | (a=1)(a=2))` |
| NOT | (!(uid=alice)) |
Negation |
| Presence | (mail=*) |
Attribute exists |
Shell quoting matters: wrap the entire filter in single quotes or escape parentheses. An empty result with exit code zero means no entry matched or your identity cannot read matching entries — check base DN, scope, and ACLs next.
A strong answer is:
"Filters are RFC 4515 expressions in parentheses — equality, wildcards, and prefix operators like & and | for AND and OR. I quote them for the shell and tighten the base DN before widening the filter."
When is SASL EXTERNAL useful?
SASL EXTERNAL authenticates using credentials already established on the transport — typically the Unix UID of the process connecting to ldapi:///. On the server host, root (via sudo) can read and modify cn=config without typing the directory administrator password.
sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b "cn=config" "(objectClass=olcDatabaseConfig)" olcSuffixThis path is local-only. Remote administration still uses a simple or SASL bind over TLS on ldap:// or ldaps://. EXTERNAL also does not help with data under dc=example,dc=com unless ACLs explicitly grant the peer identity access.
A strong answer is:
"EXTERNAL on ldapi:/// lets the local OS identity — usually root through sudo — manage cn=config without a stored config password. It is for on-host configuration work, not remote user lookups."
ldapsearch returned nothing — is that an error?
Not always. Exit code zero with no entries usually means the filter matched nothing readable at the chosen base and scope. Common causes:
- Wrong base DN or scope (entry exists but outside the subtree you searched).
- Typo in the filter (
uid=alisvsuid=alice). - ACL hides matching entries from your bind identity (try the administrator DN or ldapwhoami to confirm who you are).
- Anonymous bind on a server that requires authentication for the target OU.
Work top-down: Root DSE → suffix base scope → narrow OU → exact uid filter. Compare with an authorized bind before rewriting ACLs.
A strong answer is:
"Silent success with no rows means no readable matches — I verify base, scope, filter, and bind DN before assuming the entry is missing."
Troubleshooting
Common ldapsearch failures on the tested OpenLDAP 2.6.10 host — symptom, likely cause, and the fix to try first.
| Symptom | Likely cause | Fix |
|---|---|---|
ldap_bind: Confidentiality required (13) |
Simple bind attempted without TLS | Add -ZZ (or use ldaps://) and set LDAPTLS_CACERT to the signing CA |
ldap_start_tls: Connect error / hostname mismatch |
Certificate SAN does not match -H host |
Use the hostname on the server certificate or add -o TLS_REQSAN=allow only in a lab |
ldap_bind: Invalid credentials (49) |
Wrong bind DN or password | Confirm olcRootDN with a cn=config search; reset olcRootPW over LDAPI if needed |
Can't contact LDAP server |
Wrong URI, service down, or firewall | Check -H, ss -lntp | grep 389, and systemctl status slapd |
No such object (32) on a subtree |
Base DN does not exist, or ACL hides it from anonymous binds | Search the suffix with an authorized bind; test the base entry with -s base |
| Empty output, exit code 0 | Filter typo, wrong scope, or ACL denies read | Start at Root DSE, then test a known DN; compare with administrator bind |
Insufficient access (50) |
Bound identity lacks read permission | Bind with an authorized DN or adjust ACLs — see OpenLDAP ACL examples |
Size limit exceeded (4) |
More entries matched than -z allows |
Raise -z, narrow the filter, or use -E pr=size/noprompt for paging |
Bad search filter (87) |
Unbalanced parentheses or illegal characters | Validate RFC 4515 syntax; quote the filter for the shell |
ldap_bind: Operations error with ldapi:/// |
Forgot -Y EXTERNAL -Q or missing sudo |
Use sudo ldapsearch -Q -Y EXTERNAL -H ldapi:/// … for local config reads |
References
- OpenLDAP ldapsearch(1) manual{: target="_blank" rel="noopener" }
- RFC 4515 — LDAP string representation of search filters{: target="_blank" rel="noopener" }
- Install and configure OpenLDAP on RHEL Linux
- Configure OpenLDAP TLS on RHEL
- Manage OpenLDAP users and groups
- OpenLDAP ACL examples
- OpenLDAP cn=config and MDB backend
