ldapsearch Command in Linux: Syntax, Filters & Practical Examples

ldapsearch queries LDAP directory entries from the command line. It can search anonymously, use a simple bind protected by StartTLS, or authenticate locally over LDAPI with SASL EXTERNAL.

Published

Updated

Read time 15 min read

Reviewed byDeepak Prasad

ldapsearch Command in Linux: Syntax, Filters & Practical Examples
About ldapsearch queries LDAP directory entries from the command line. It can search anonymously, use a simple bind protected by StartTLS, or authenticate locally over LDAPI with SASL EXTERNAL.
Tested on Rocky Linux 10.2; OpenLDAP 2.6.10; openldap-clients from EPEL
Package openldap-clients (apt/deb) · openldap-clients (dnf/rpm)
Man page ldapsearch(1)
Privilege unprivileged for anonymous or network binds; root for LDAPI EXTERNAL
Distros RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream (openldap-clients package).
Related guide

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:

text
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 attributes

Positional arguments after the options:

  1. Filter — RFC 4515 string in parentheses. Omit it only when you pass -f filterfile.
  2. 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):

text
(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 matches

Scope 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.

bash
ldapsearch -x -LLL -H ldap://localhost -s base -b "" namingContexts

Sample output:

output
dn:
namingContexts: dc=example,dc=com

The 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.

bash
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 mail

Sample output:

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:

bash
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 mail

Sample output:

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:

bash
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 cn

Sample output:

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: alice

Order 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.

bash
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 uid

Sample output:

output
Enter LDAP Password:
dn: uid=alice,ou=people,dc=example,dc=com
cn: Alice Example
uid: alice

Broad (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.

bash
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))" dn

Sample output:

output
Enter LDAP Password:
dn: uid=bob,ou=people,dc=example,dc=com

dn: uid=alice,ou=people,dc=example,dc=com

The 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.

bash
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=*)" dn

Sample output:

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.

bash
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:

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.

bash
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:

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: FALSE

Operational 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.

bash
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))" dn

Sample output:

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.

bash
ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "dc=example,dc=com" -LLL "(objectClass=organizationalUnit)" ou

Sample output:

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.

bash
ldapsearch -x -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "dc=example,dc=com" -s base "(objectClass=*)"

Sample output:

output
Enter LDAP Password:
ldap_bind: Confidentiality required (13)
	additional info: confidentiality required

Add -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.

bash
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)" cn

The 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.

bash
ldapsearch -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -b "dc=example,dc=com" -s base -LLL "(objectClass=*)" dc objectClass

Sample output:

output
Enter LDAP Password:
dn: dc=example,dc=com
objectClass: top
objectClass: dcObject
objectClass: organization
dc: example

This 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.

bash
sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b "cn=config" "(objectClass=olcDatabaseConfig)" olcSuffix

Sample output:

output
dn: olcDatabase={2}mdb,cn=config
olcSuffix: dc=example,dc=com

This confirms which dynamic database serves the suffix.


ldapsearch — when to use / when not

Use ldapsearch whenUse something else when
  • You need to discover, verify, or export readable directory data
  • You need to test a filter, base DN, or access rule
  • You need a read-only view of cn=config over LDAPI

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

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.

bash
sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b "cn=config" "(objectClass=olcDatabaseConfig)" olcSuffix

This 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:

  1. Wrong base DN or scope (entry exists but outside the subtree you searched).
  2. Typo in the filter (uid=alis vs uid=alice).
  3. ACL hides matching entries from your bind identity (try the administrator DN or ldapwhoami to confirm who you are).
  4. 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

Rohan Timalsina

is a technical writer and Linux enthusiast who writes practical guides on Linux commands and system administration. He focuses on simplifying complex topics through clear explanations.