ldapadd Command in Linux: Syntax, LDIF & Practical Examples

ldapadd creates LDAP entries from LDIF input. Use a StartTLS-protected simple bind for directory data or SASL EXTERNAL over LDAPI for local cn=config schema work.

Published

Updated

Read time 10 min read

Reviewed byDeepak Prasad

ldapadd Command in Linux: Syntax, LDIF & Practical Examples
About ldapadd creates LDAP entries from LDIF input. Use a StartTLS-protected simple bind for directory data or SASL EXTERNAL over LDAPI for local cn=config schema work.
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 ldapadd(1)
Privilege bind DN with write access; 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; openldap-clients from EPEL.

ldapadd — quick reference

Add directory entries

ldapadd reads LDIF from standard input unless -f names a file. It is the ldapmodify binary in add mode.

When to use Command
Add records from an LDIF file over StartTLS ldapadd -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -f add-user.ldif
Add records and provide the lab password on the command line ldapadd -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -w 'PASSWORD' -f add-user.ldif
Pipe LDIF from standard input ldapadd -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W < add-user.ldif
Read the password from a protected file instead of -w ldapadd -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -y /root/ldap.pass -f add-user.ldif

Batch recovery and preview

Use these flags when a large import stops partway through or you want to rehearse before writing.

When to use Command
Continue processing later records after an error ldapadd -c -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -f batch.ldif
Resume from a specific LDIF line number after a failure ldapadd -j 11 -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -f batch.ldif
Write skipped or failed records to another LDIF file ldapadd -c -S skipped.ldif -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -f batch.ldif
Preview changes without sending them to the server ldapadd -n -v -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -f add-user.ldif

Debugging and local configuration

When to use Command
Print an operation transcript ldapadd -v -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -f add-user.ldif
Raise the LDAP client debug level ldapadd -d 1 -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -f add-user.ldif
Add a local schema or cn=config record sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f schema.ldif

Help

When to use Command
Show usage (no -h on this build) ldapadd 2>&1 | head
Print version and exit ldapadd -VV

ldapadd — command syntax

ldapadd shares the modify utility syntax. Synopsis from the OpenLDAP 2.6.10 client on the tested host:

text
ldapadd [-V[V]] [-d debuglevel] [-n] [-v] [-c] [-f file] [-j lineno]
        [-S file] [-M[M]] [-x] [-D binddn] [-W] [-w passwd] [-y passwdfile]
        [-H ldapuri] [-P {2|3}] [-e [!]<ext>[=<extparam>]]
        [-E [!]<ext>[=<extparam>]] [-o opt[=optparam]] [-I] [-Q]
        [-Y mech] [-Z[Z]]

The input must be valid LDIF. Build user records in the OpenLDAP user and group management guide before loading them; install OpenLDAP on RHEL first if the server and dc=example,dc=com suffix are not yet in place. For TLS trust and -ZZ, see configure OpenLDAP TLS on RHEL.


ldapadd — command examples

Essential Add a user from an LDIF file

Prepare a user record under ou=people,dc=example,dc=com. The server on this lab requires StartTLS before a simple bind.

LDIF for the add:

text
dn: uid=alice,ou=people,dc=example,dc=com
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
cn: Alice Example
sn: Example
uid: alice
mail: [email protected]

Load it with the directory administrator:

bash
ldapadd -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -f /root/alice.ldif

Sample output:

output
Enter LDAP Password:
adding new entry "uid=alice,ou=people,dc=example,dc=com"

The adding new entry line with the full DN is the confirmation that the server accepted the record.

Essential Verify the added entry

Search the exact DN after an add. A base-scope read catches a wrong suffix or mistyped RDN immediately.

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

Sample output:

output
Enter LDAP Password:
dn: uid=alice,ou=people,dc=example,dc=com
uid: alice
cn: Alice Example
mail: [email protected]

When ACLs allow anonymous read, you can omit the bind; otherwise use an authorized DN as shown here.

Essential Recognize an existing DN

Re-running an add against the same DN does not update it; LDAP returns error 68.

bash
ldapadd -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -f /root/alice.ldif

Sample output:

output
Enter LDAP Password:
ldap_add: Already exists (68)
adding new entry "uid=alice,ou=people,dc=example,dc=com"

Use ldapmodify for an existing entry rather than deleting and recreating it.

Common Add an entry from standard input

Omit -f when a here-document or pipe feeds LDIF. This is the same add semantics as a file.

bash
ldapadd -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -w 'PASSWORD' < /root/carol.ldif

Sample output:

output
adding new entry "uid=carol,ou=people,dc=example,dc=com"

Shell redirection keeps short one-off adds out of temporary files on disk.

Common Continue through a batch after one bad record

-c reports errors but continues with later LDIF records, which is useful when importing an inspected batch.

bash
ldapadd -c -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -W -f /root/people-batch.ldif

Sample output:

output
Enter LDAP Password:
ldap_add: Already exists (68)
adding new entry "uid=alice,ou=people,dc=example,dc=com"

adding new entry "uid=bob,ou=people,dc=example,dc=com"

Review every error afterward; -c prevents an early stop but does not make failed records succeed.

Common Preview an add with `-n`

-n shows what would be sent without modifying the directory. Pair it with -v to see attribute values in the transcript.

bash
ldapadd -n -v -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -w 'PASSWORD' -f /root/carol.ldif

Sample output:

output
add objectClass:
	top
	person
	organizationalPerson
	inetOrgPerson
add cn:
	Carol Example
add uid:
	carol
!adding new entry "uid=carol,ou=people,dc=example,dc=com"

The leading ! on the add line marks a dry-run operation that was not applied.

Common Resume a batch from a line number

After a failed import, -j lineno skips earlier lines in the LDIF file. Jump to the dn: line of the next record you still need to load.

bash
ldapadd -j 11 -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -w 'PASSWORD' -f /root/people-batch.ldif

Sample output:

output
adding new entry "uid=bob,ou=people,dc=example,dc=com"

Line numbers come from nl -ba batch.ldif; start at the dn: of the first record that did not succeed.

Advanced Capture skipped records with `-S`

-S file writes records that could not be added into a separate LDIF, including a comment with the error.

bash
ldapadd -c -S /root/skipped.ldif -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -w 'PASSWORD' -f /root/people-batch.ldif

Sample output:

output
ldap_add: Already exists (68)
adding new entry "uid=alice,ou=people,dc=example,dc=com"

adding new entry "uid=bob,ou=people,dc=example,dc=com"

The skipped file preserves the failed record for correction:

output
# Error: Already exists (68) (line=1)
dn: uid=alice,ou=people,dc=example,dc=com
objectClass: top
...

Fix the skipped LDIF and re-import only those entries.

Advanced Read the bind password from a file

-y passwdfile keeps the administrator password out of shell history. Restrict the file to the invoking user.

bash
ldapadd -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -y /root/ldap.pass -f /root/carol.ldif

Sample output:

output
ldap_add: Already exists (68)
adding new entry "uid=carol,ou=people,dc=example,dc=com"

Error 68 here only means the entry was already present from an earlier successful add.

Advanced Show an add operation verbosely

Use -v when a script needs an operation transcript rather than only the success line.

bash
ldapadd -v -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -w 'PASSWORD' -f /root/bob.ldif

Sample output:

output
ldap_initialize( ldap://localhost:389/??base )
add objectClass:
	top
	person
	organizationalPerson
	inetOrgPerson
add cn:
	Bob Example
adding new entry "uid=bob,ou=people,dc=example,dc=com"

Verbose mode exposes the target object without revealing the bind password.

Advanced Raise the client debug level with `-d`

-d 1 prints connection and bind steps when StartTLS or URI selection fails before any add is attempted.

bash
ldapadd -d 1 -x -ZZ -H ldap://localhost -D "cn=admin,dc=example,dc=com" -w 'PASSWORD' -f /root/bob.ldif

Sample output:

output
ldap_url_parse_ext(ldap://localhost)
ldap_create
ldap_url_parse_ext(ldap://localhost:389/??base)
ldap_extended_operation_s
ldap_connect_to_host: TCP localhost:389
ldap_new_socket: 6

Trim higher debug levels in articles; they flood the terminal quickly on a busy host.

Advanced Add local schema through LDAPI EXTERNAL

For cn=config, use the local socket and the operating-system root identity instead of a directory password. Run this with sudo after validating the schema LDIF against cn=config and MDB.

bash
sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f /root/example-schema.ldif

Sample output:

output
adding new entry "cn=example,cn=schema,cn=config"

Schema changes affect the server globally, so take a configuration backup first.


ldapadd — when to use / when not

Use ldapadd whenUse something else when
  • You have a new entry represented as LDIF
  • You are loading an approved initial dataset under dc=example,dc=com
  • You need add semantics and want existing DNs to fail with error 68
  • You are rehearsing an import with -n before a production run
  • You need to change an existing attribute → ldapmodify
  • You need to inspect a DN first → ldapsearch
  • You need to remove an entry → ldapdelete
  • You are bulk-loading an offline database → slapadd with slapd stopped

ldapadd vs ldapmodify

ldapadd ldapmodify
Default action Creates new entries Applies LDIF modifications
Existing DN Fails with error 68 Can add, replace, or delete attributes
Input Entry LDIF changetype: modify LDIF
Add mode Always active -a switches to add semantics

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.


ldapadd — interview corner

Practice these before exams or directory-service standups. Each card explains the idea in plain language, then ends with a short answer you can say aloud.

How does ldapadd differ from ldapmodify?

ldapadd always creates entries; it is the ldapmodify binary invoked in add mode (-a is implicit). A duplicate DN therefore fails with error 68 instead of being changed.

A strong answer is:

“Use ldapadd for a new DN and ldapmodify for attributes on an existing DN.”

What input does ldapadd require?

It reads LDIF from standard input or the file named by -f. Each record needs a DN, object classes, and the attributes required by those classes.

A strong answer is:

“The input is LDIF, not a list of shell arguments.”

What does ldapadd -c do?

It continues with subsequent records after an error. Failed records still need correction and another import; combine it with -S to capture what was skipped.

A strong answer is:

“It is for batch imports where I want a complete error list without stopping at the first failure.”

Why use -ZZ with ldapadd?

-ZZ requires StartTLS before the simple bind, preventing a cleartext password fallback when the server advertises the confidentiality requirement.

A strong answer is:

“It makes TLS mandatory for the bind, which is essential on this LDAP endpoint.”

What is the purpose of ldapadd -n?

-n prints the operations that would run without sending them to the server. Pair it with -v to review attribute values before a large import.

A strong answer is:

“I rehearse the LDIF with -n -v, fix schema or ACL issues, then run the same file without -n.”

When would you use ldapadd -j?

-j lineno skips the first lines of an LDIF file and resumes processing. After a partial failure, jump to the dn: line of the next record instead of re-adding everything.

A strong answer is:

“I note the failing line number, fix the record or use -j to start at the next dn, and finish the batch.”


Troubleshooting

Common ldapadd failures on a StartTLS-enabled OpenLDAP 2.6 lab — symptom, likely cause, and the fix to try first.

Symptom Likely cause Fix
Already exists (68) The LDIF DN is already present Search the DN, then use ldapmodify if an update is intended.
Object class violation (65) Required object class or attribute is missing Check the LDIF against the active schema; see manage users and groups.
No such object (32) Parent OU or suffix does not exist Create the parent container first or fix the DN base.
Insufficient access (50) Bind DN lacks write ACLs Use an authorized DN or adjust ACLs.
Confidentiality required (13) Simple bind did not negotiate TLS Add -ZZ and trust the server certificate per the TLS guide.
Invalid credentials (49) Wrong administrator DN or password Confirm cn=admin,dc=example,dc=com and the olcRootPW hash on the server.
Can't contact LDAP server slapd down, wrong URI, or firewall Check systemctl status slapd and the -H URI.
Dry-run looks correct but live add fails Schema, ACL, or duplicate DN only visible after bind Remove -n, add -v, and read the first server error line.
-j imports a broken partial entry Resume line points inside a record, not at dn: Use nl -ba file.ldif and restart at the next dn: line.

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.