Modern 389 Directory Server releases default to LMDB for new instances. Berkeley DB remains available only on distributions that ship the optional BDB backend package, and upstream is removing BDB support over time. Updating 389-ds-base through dnf or your package manager does not automatically convert an existing BDB-backed instance to LMDB.
A supported 389 Directory Server BDB to LMDB migration therefore requires a deliberate database-backend change. During dsctl dblib bdb2mdb, the instance is unavailable while backends export, nsslapd-backend-implement changes to mdb, and data imports into LMDB. The tool leaves old BDB files in place until you validate the result and run cleanup.
This lab uses three instances on ldap1.example.com:
| Instance | Role in this guide | LDAP port |
|---|---|---|
bdb-lab |
Standalone BDB conversion in Steps 4–5 and 7 | 20389 |
ldap1 |
LMDB supplier that stays online during Step 6 | 389 |
bdb-consumer |
BDB consumer replica converted in Step 6 | 21389 |
Steps 4–5 and 7 walk through bdb-lab with suffix dc=bdblab,dc=example,dc=com. Step 6 converts bdb-consumer, which replicates dc=example,dc=com from the ldap1 supplier while that supplier remains on LMDB. Replace instance names, paths, and ports with your deployment values.
Before you start:
- Install 389 Directory Server — instance layout and
dscreatebasics - Back Up and Restore 389 Directory Server — native backup before backend conversion
Tested on: Rocky Linux 10.2; 389 Directory Server 3.2.0.
Step 1: Check whether the instance uses BDB or LMDB
Before you schedule downtime, confirm the 389 Directory Server database backend on every instance you plan to convert.
List instances on the host:
Offline instance work in this section uses dsctl commands.
dsctl -lslapd-bdb-consumer
slapd-bdb-lab
slapd-ldap1
slapd-ldap2Use the short instance name in later dsctl and dsconf commands. This lab converts bdb-lab in the standalone path and bdb-consumer in the replicated path.
When the instance is running, read the configured backend implementation:
Online configuration in this section uses dsconf commands.
dsconf bdb-lab backend config get | grep nsslapd-backend-implementnsslapd-backend-implement: bdbA value of bdb means this guide applies. A value of mdb means the instance already uses LMDB and does not need dsctl dblib bdb2mdb.
When the instance is stopped, read the same attribute from dse.ldif:
grep nsslapd-backend-implement /etc/dirsrv/slapd-bdb-lab/dse.ldifnsslapd-backend-implement: bdbThe offline copy should match the value reported by dsconf when the instance was last running.
Confirm the installed package build and whether Berkeley DB libraries are available on your platform:
rpm -q 389-ds-base 389-ds-base-bdb389-ds-base-3.2.0-8.el10_2.x86_64
389-ds-base-bdb-3.2.0-8.el10_2.x86_64When both packages are installed, the NEVRAs should match on the same release.
389-ds-base-bdb compatibility package. That does not make BDB a supported backend on Red Hat Enterprise Linux 10 or Red Hat Directory Server 13. Official RHEL 10 documentation states that the system libdb implementation is no longer available, BDB instances are no longer supported, and existing instances should be migrated to LMDB before or during the platform move. On supported Red Hat deployments, migrate BDB instances on the older supported platform before moving to RHEL 10 or RHDS 13, or follow Red Hat Support guidance. Do not tell RHEL 10 administrators to enable an unrelated community repository or install community compatibility RPMs.
On Rocky Linux 10 only, when you need the compatibility package for lab or legacy-instance testing, enable CRB and install the matching build with dnf command:
dnf config-manager --set-enabled crbThe command exits silently when CRB is enabled.
dnf install -y 389-ds-base-bdbThe install completes without errors when the CRB repository provides a matching 389-ds-base-bdb build.
Verify the installed NEVRAs match:
rpm -q 389-ds-base 389-ds-base-bdb389-ds-base-3.2.0-8.el10_2.x86_64
389-ds-base-bdb-3.2.0-8.el10_2.x86_64Both packages should report the same release suffix before you create or migrate a BDB instance. Red Hat documents automated dsctl BDB-to-LMDB conversion for Directory Server 12.5 and later. Upstream 389 DS 3.x defaults new instances to LMDB. Read the release notes for your exact package stream before you plan production downtime.
Step 2: Choose the appropriate migration method
| Environment | Recommended method |
|---|---|
| Supported release with enough local disk space | dsctl dblib bdb2mdb |
| LDIF files must use another filesystem | dsctl dblib bdb2mdb --tmpdir PATH |
| LMDB map size must be set manually before import | Manual export and import |
| Automated conversion fails | Manual migration or replica rebuild |
| Replicated instance you can rebuild from a supplier | Reinitialize or rebuild as LMDB |
Release without dblib bdb2mdb support |
Upgrade to a supported build first, then migrate |
| FreeIPA or Red Hat IdM deployment | Follow IdM-specific documentation |
Use automated in-place conversion when the installed dsctl build supports dblib bdb2mdb and the host has room for exported LDIF files, the new LMDB map, and the original BDB files until cleanup. When /var/lib/dirsrv is too small, point --tmpdir at a filesystem with enough free space instead of switching immediately to a fully manual workflow.
Step 3: Prepare for the migration
Complete these checks before you remove the instance from client traffic:
- Confirm
dsctl INSTANCE dblib bdb2mdbexists on the installed build. - Install applicable errata for your Directory Server release.
- Run
dsctl INSTANCE healthcheckand resolve material errors. - Verify LDAP and LDAPS access for applications that depend on the instance.
- Record every backend name and suffix with
dsconf INSTANCE backend suffix list. - Estimate disk space under
/var/lib/dirsrv/slapd-INSTANCE/. - Create a native backup while the instance still runs BDB.
- Schedule downtime and stop application writes on standalone hosts.
Run a health check on the BDB instance:
dsctl bdb-lab healthcheckHealthcheck complete.
No issues found.On a BDB instance, the health check may also report that BDB is deprecated. That warning is expected until you complete the migration.
Measure database size and free space on the instance path:
du -sh /var/lib/dirsrv/slapd-bdb-lab/db476K /var/lib/dirsrv/slapd-bdb-lab/dbConfirm the filesystem that holds the instance still has enough headroom for export, import, and cleanup:
df -h /var/lib/dirsrv/slapd-bdb-labFilesystem Size Used Avail Use% Mounted on
/dev/mapper/rlm-root 14G 11G 2.3G 83% /Calculate the initial LMDB map size by adding the sizes of all backend database directories and adding at least a 20% safety margin. When the BDB files, migration LDIF, and LMDB database share the same filesystem, plan free space of at least twice that calculated LMDB map size—not merely twice the current database-directory size. When you use --tmpdir, verify sufficient capacity on both the temporary filesystem and the filesystem containing the instance database.
For example:
du -sch /var/lib/dirsrv/slapd-bdb-lab/db/*/200K /var/lib/dirsrv/slapd-bdb-lab/db/userroot
476K totalThe measured total was only 476 KiB in this lab. The 2.3 GiB free on / was therefore more than enough for this tiny test database, but it is not a general sizing rule for production directories.
dse.ldif copy until LMDB validation completes.
Create and verify a native BDB backup before conversion:
backup="/var/lib/dirsrv/slapd-bdb-lab/bak/bdb-lab-pre-mdb"The variable holds the backup directory path used in the next commands.
Create the online backup while the instance still runs BDB:
dsconf bdb-lab backup create "$backup"The backup create task has finished successfullyPreserve the configuration snapshot and package list with the backup:
cp -a /etc/dirsrv/slapd-bdb-lab/dse.ldif "$backup/dse.ldif.pre-migration"The copy gives you the exact BDB-era configuration if you need to compare settings later.
Record the package versions installed at migration time:
rpm -q 389-ds-base 389-ds-base-bdb | tee "$backup/package-versions.txt"tee writes the NEVRAs into the backup directory and prints them to the terminal.
389-ds-base-3.2.0-8.el10_2.x86_64
389-ds-base-bdb-3.2.0-8.el10_2.x86_64Create and verify a checksum manifest:
(
cd "$backup"
find . -type f ! -name SHA256SUMS -print0 |
sort -z |
xargs -0 sha256sum > SHA256SUMS
sha256sum -c SHA256SUMS
)Every file in the backup directory should report OK.
./config_files/cert9.db: OK
./config_files/dse.ldif: OK
...A BDB-era archive contains Berkeley DB files rather than LMDB data.mdb files; the checksum workflow is the same. The complete isolated-restore workflow lives in Back Up and Restore 389 Directory Server.
Record the entry count before conversion:
ldapsearch -LLL -o ldif-wrap=no -Y EXTERNAL -H ldapi://%2Frun%2Fslapd-bdb-lab.socket -b "dc=bdblab,dc=example,dc=com" "(objectClass=*)" dn | grep -Ec '^dn::? '13Record this count so you can compare against the post-migration search later.
Step 4: Migrate BDB to LMDB with dsctl dblib bdb2mdb
This is the preferred method to migrate 389 Directory Server to LMDB on a standalone instance when disk space is sufficient.
Confirm the installed command exposes --tmpdir on your build:
dsctl bdb-lab dblib bdb2mdb --helpusage: dsctl [-v] [-j] [instance] dblib bdb2mdb [-h] [--tmpdir TMPDIR]
...
--tmpdir TMPDIR ldif migration files directory path.Remove the instance from client traffic, then run the conversion. bdb2mdb manages the instance stop and start internally: it stops the server, exports BDB backends, updates dse.ldif, imports into LMDB, and starts the instance again. You still need a maintenance window because the directory remains unavailable during export, conversion, and import.
Run the automated conversion:
dsctl bdb-lab dblib bdb2mdbRepresentative progress from the tested lab run:
INFO: Required space for LDIF files is about 24.0 KB
INFO: Required space for DBMAP files is about 240.0 KB
INFO: Required number of dbi is 128
INFO: Backends exportation 100%
INFO: Updating dse.ldif file
INFO: Backends importation 100%
INFO: Migration from Berkeley database to lmdb is done.The command calculates an initial LMDB map size (nsslapd-mdb-max-size) and leaves the old BDB files in place until you run cleanup. Large production databases can take considerable time; do not interrupt the process only because the terminal appears idle between progress lines.
On affected RHEL 10-derived builds, a standalone conversion can display error 97 while checking for a nonexistent replication changelog. Do not ignore a failed conversion generally; ignore this specific message only when the remaining output confirms that export, configuration update, and LMDB import completed.
If dsctl healthcheck incorrectly reports that BDB is still active after dsconf backend config get reports mdb, rerun the check with the backend library set explicitly:
NSSLAPD_DB_LIB=mdb dsctl bdb-lab healthcheckThat workaround addresses false DSBLE0005 or DSBLE0006 warnings on some RHEL 10-derived builds. Do not run dblib cleanup merely to silence a false health-check warning when validation otherwise passes.
When /var/lib/dirsrv does not have enough room for temporary LDIF files, create a migration directory owned by dirsrv on another filesystem:
install -d -o dirsrv -g dirsrv -m 750 /mnt/389ds-migrationRun the conversion with --tmpdir pointing at that path:
dsctl bdb-lab dblib bdb2mdb --tmpdir /mnt/389ds-migrationThe conversion checks free space on the temporary path separately from the database directory.
Verify the instance is running after conversion:
dsctl bdb-lab statusInstance "bdb-lab" is runningDo not run dsctl dblib cleanup yet.
Step 5: Verify the LMDB migration
Confirm the backend implementation changed:
dsconf bdb-lab backend config get | grep nsslapd-backend-implementnsslapd-backend-implement: mdbRead the configured LMDB maximum map size:
dsconf bdb-lab backend config get | grep nsslapd-mdb-max-sizensslapd-mdb-max-size: 41943044194304 bytes is 4 MiB. The tested lab received that small map because the suffix is small. Production instances need headroom based on measured database size plus a safety margin. See Tune LMDB, Entry Cache and DN Cache in 389 Directory Server before you accept the auto-calculated value on a large directory.
List LMDB files in the database directory:
ls -la /var/lib/dirsrv/slapd-bdb-lab/db/-rw-------. 1 dirsrv dirsrv 118784 Jul 18 23:13 data.mdb
-rw-r--r--. 1 dirsrv dirsrv 72 Jul 18 23:13 INFO.mdb
-rw-------. 1 dirsrv dirsrv 8192 Jul 18 23:13 lock.mdb
drwx------. 2 dirsrv dirsrv 4096 Jul 18 23:13 userrootdata.mdb, INFO.mdb, and lock.mdb confirm LMDB is active. The remaining userroot/ directory holds old BDB files until cleanup.
Verify the entry count matches the pre-migration baseline:
ldapsearch -LLL -o ldif-wrap=no -x -H ldap://127.0.0.1:20389 -D "cn=Directory Manager" -y /root/bdb-lab-dm.pw -b "dc=bdblab,dc=example,dc=com" "(objectClass=*)" dn | grep -Ec '^dn::? '13The post-migration count matches the pre-migration baseline of 13 entries.
Run the health check again. Before cleanup, the linter reports leftover BDB files:
dsctl bdb-lab healthcheck[1] DS Lint Error: DSBLE0004
...
Files for both MDB and BDB databases have been found.
...
Run 'dsctl <instance> dblib cleanup' to remove old database files...That warning is expected until cleanup removes the obsolete BDB artifacts.
Validate LDAP, LDAPS, and indexed searches
Test authenticated LDAP:
ldapwhoami -x -H ldap://127.0.0.1:20389 -D "cn=Directory Manager" -y /root/bdb-lab-dm.pwdn: cn=directory managerA successful bind confirms LDAP authentication still works on the converted backend.
Test LDAPS with the trust anchor your clients use. This lab instance listens on LDAPS port 20636 with the self-signed certificate created during dscreate:
LDAPTLS_CACERT="/tmp/389ds-selfsigned-ca.pem" ldapwhoami -x -H ldaps://ldap1.example.com:20636 -D "cn=Directory Manager" -y /root/bdb-lab-dm.pwdn: cn=directory managerLDAPS succeeds when the client trusts the instance certificate or CA.
Verify an indexed application-style search:
ldapsearch -LLL -x -H ldap://127.0.0.1:20389 -D "cn=Directory Manager" -y /root/bdb-lab-dm.pw -b "dc=bdblab,dc=example,dc=com" "(uid=demo_user)" dn uiddn: uid=demo_user,ou=people,dc=bdblab,dc=example,dc=com
uid: demo_userThe indexed uid search returns the same entry as before migration.
Create the first LMDB-native backup before you discard BDB rollback files:
dsconf bdb-lab backup create /var/lib/dirsrv/slapd-bdb-lab/bak/bdb-lab-first-lmdbThe backup create task has finished successfullyChecksum or restore-test that archive using the workflow in Back Up and Restore 389 Directory Server.
Review recent service logs:
journalctl -u [email protected] --since "30 minutes ago" --no-pagerJul 18 23:13:13 ldap1.example.com systemd[1]: Started [email protected] - 389 Directory Server bdb-lab..
Jul 18 23:13:13 ldap1.example.com ns-slapd[20901]: [18/Jul/2026:23:13:13.012451217 +0530] - INFO - slapd_daemon - slapd started. Listening on All Interfaces port 20389 for LDAP requestsThe journal should show a clean start after the LMDB import.
Only proceed to cleanup after LDAP, LDAPS, indexed searches, plug-ins, replication when enabled, and application checks all pass.
Step 6: Perform a rolling conversion in a replicated topology
A rolling Berkeley DB to LMDB migration proceeds one Directory Server instance at a time. In the usual one-instance-per-host topology, this is also a host-by-host migration. When a host runs multiple Directory Server instances, convert and validate each instance separately.
This lab keeps the ldap1 supplier on LMDB and converts the bdb-consumer replica on the same host. BDB and LMDB replicas can coexist briefly because replication transfers LDAP changes, not native database files. Do not convert every writable supplier simultaneously.
Confirm replication health before conversion
From the supplier that stays online, list agreements and read synchronization state:
dsconf -D "cn=Directory Manager" -y /root/dm.pw ldap1 replication status --suffix "dc=example,dc=com"{'agmt-name': ['ldap1-to-bdb-consumer'], 'replica': ['ldap1.example.com:21389'], 'replica-enabled': ['on'], 'replication-status': ['Not in Synchronization: supplier (Unknown) consumer (Unknown) State (green) Reason (error (0) replica acquired successfully: incremental update succeeded)'], 'replication-lag-time': ['unavailable'], 'last-update-status': ['Error (0) Replica acquired successfully: Incremental update succeeded']}Confirm the supplier and the replica you plan to convert are synchronized. Use the hostname and LDAP port from your agreement output, and treat ds-replcheck as the authoritative check when replication-status looks ambiguous:
ds-replcheck state -D "cn=Directory Manager" -y /root/dm.pw -m ldap://ldap1.example.com:389 -r ldap://ldap1.example.com:21389 -b "dc=example,dc=com"Replication State: Supplier and Replica are in perfect synchronizationDo not start the conversion while agreements report unexplained lag or a disabled replica.
Convert one replica
Remove every client endpoint served by bdb-consumer from rotation. Create and verify a pre-migration backup on the replica:
backup="/var/lib/dirsrv/slapd-bdb-consumer/bak/bdb-consumer-pre-mdb"dsconf bdb-consumer backup create "$backup"The backup create task has finished successfullyRecord the entry count on the BDB replica before conversion:
ldapsearch -LLL -o ldif-wrap=no -x -H ldap://127.0.0.1:21389 -D "cn=Directory Manager" -y /root/bdb-consumer-dm.pw -b "dc=example,dc=com" "(objectClass=*)" dn | grep -Ec '^dn::? '769Run the automated conversion on the replica:
dsctl bdb-consumer dblib bdb2mdbINFO: Required space for LDIF files is about 5.7 MB
INFO: Required space for DBMAP files is about 9.0 MB
INFO: Required number of dbi is 128
INFO: Backends exportation 100%
INFO: Updating dse.ldif file
INFO: Backends importation 100%
INFO: Migration from Berkeley database to lmdb is done.Confirm the backend changed and the instance restarted:
dsconf bdb-consumer backend config get | grep nsslapd-backend-implementnsslapd-backend-implement: mdbdsctl bdb-consumer statusInstance "bdb-consumer" is runningVerify the entry count matches the pre-migration baseline:
ldapsearch -LLL -o ldif-wrap=no -x -H ldap://127.0.0.1:21389 -D "cn=Directory Manager" -y /root/bdb-consumer-dm.pw -b "dc=example,dc=com" "(objectClass=*)" dn | grep -Ec '^dn::? '769Review the service journal for a clean restart after import:
journalctl -u [email protected] --since "30 minutes ago" --no-pagerJul 18 23:13:39 ldap1.example.com systemd[1]: Started [email protected] - 389 Directory Server bdb-consumer..
Jul 18 23:13:39 ldap1.example.com ns-slapd[21019]: [18/Jul/2026:23:13:39.483545796 +0530] - INFO - slapd_daemon - slapd started. Listening on All Interfaces port 21389 for LDAP requestsVerify replication before you convert the next replica
From the supplier, confirm the converted replica caught up:
dsconf -D "cn=Directory Manager" -y /root/dm.pw ldap1 replication status --suffix "dc=example,dc=com"{'agmt-name': ['ldap1-to-bdb-consumer'], 'replica': ['ldap1.example.com:21389'], 'replica-enabled': ['on'], 'replication-status': ['Not in Synchronization: supplier (Unknown) consumer (Unknown) State (green) Reason (error (0) replica acquired successfully: incremental update succeeded)'], 'replication-lag-time': ['unavailable'], 'last-update-status': ['Error (0) Replica acquired successfully: Incremental update succeeded']}ds-replcheck state -D "cn=Directory Manager" -y /root/dm.pw -m ldap://ldap1.example.com:389 -r ldap://ldap1.example.com:21389 -b "dc=example,dc=com"Replication State: Supplier and Replica are in perfect synchronizationA successful ds-replcheck result and a successful last-update-status mean the converted replica can rejoin client traffic. Complete Step 7 on that instance before you convert the next replica.
Convert the remaining replicas
Repeat the same sequence on each BDB-backed replica:
- Confirm surviving suppliers are healthy
- Drain the instance from client traffic
- Create and verify a pre-migration backup
- Record the entry count
- Run
dsctl INSTANCE dblib bdb2mdb - Validate backend type, entry counts, LDAP, and replication state
- Run cleanup after validation
- Return the instance to client traffic before you convert the next replica
Running bdb2mdb on one instance does not convert other Directory Server instances on the same host. For a disposable consumer, reinitializing from a healthy supplier is often safer than in-place conversion when another current supplier is available.
Step 7: Clean up the old BDB data
Run cleanup only after the validation steps in Step 5 or Step 6 succeed.
Remove obsolete BDB database files:
dsctl bdb-lab dblib cleanupcleanup dbmapdir=/var/lib/dirsrv/slapd-bdb-lab/db dbhome=/dev/shm/slapd-bdb-lab dblib=mdbdblib cleanup removes obsolete database files for the inactive backend implementation. Depending on the installed build, generated migration LDIF and changelog-export files may remain. In 389 DS 3.2.0, the source leaves __dblib-*.ldif files in place while removing the old BDB database directories.
Inspect the instance LDIF directory after cleanup:
find /var/lib/dirsrv/slapd-bdb-lab/ldif -maxdepth 1 -type f \( -name '__dblib-*.ldif' -o -name '__dblib-*.cl5.dbtxt' \) -ls554633 12 -rw------- 1 dirsrv dirsrv 9350 Jul 18 23:13 /var/lib/dirsrv/slapd-bdb-lab/ldif/__dblib-userroot.ldifWhen you used --tmpdir, inspect that directory only if it exists:
if [ -d /mnt/389ds-migration ]; then
find /mnt/389ds-migration -maxdepth 1 -type f -ls
fiThis lab did not use --tmpdir, so skip the command or expect no output when the directory does not exist.
Remove migration LDIF files only after validation and any required retention period. They can contain the complete directory dataset, including password hashes:
find /var/lib/dirsrv/slapd-bdb-lab/ldif -maxdepth 1 -type f \( -name '__dblib-*.ldif' -o -name '__dblib-*.cl5.dbtxt' \) -delete-delete produces no output when the files are removed successfully.
Confirm the health check is clean:
dsctl bdb-lab healthcheckHealthcheck complete.
No issues found.List the database directory to confirm only LMDB files remain:
ls -la /var/lib/dirsrv/slapd-bdb-lab/db/-rw-------. 1 dirsrv dirsrv 118784 Jul 18 23:13 data.mdb
-rw-r--r--. 1 dirsrv dirsrv 72 Jul 18 23:13 INFO.mdb
-rw-------. 1 dirsrv dirsrv 8192 Jul 18 23:13 lock.mdbOnly LMDB database files remain under db/.
Step 8: Manual migration and recovery
Perform a manual BDB-to-LMDB migration
Use manual LDIF export and import when:
dsctl dblib bdb2mdbcannot complete- You must set
nsslapd-mdb-max-sizemanually before import - You need to inspect or edit intermediate LDIF files
Use dsctl dblib bdb2mdb --tmpdir PATH when the issue is only separate LDIF storage. Reserve the manual sequence below for cases that require explicit control over map size or LDIF content.
Keep the instance removed from load balancers, DNS service records, application connection lists, monitoring writes, and administrative automation from the first offline export until all LMDB imports and validation checks finish.
The temporary starts in this procedure exist only so dsconf can modify the configuration. They do not return the instance to production.
The write freeze applies across all backends until every corresponding LDIF file has been imported.
This example has one data backend named userroot. The database implementation setting is global to the instance, so every configured backend must be exported before switching and imported afterward. List all configured suffixes and repeat the export and import commands for every backend before returning the instance to service:
dsconf bdb-lab backend suffix listdc=bdblab,dc=example,dc=com (userroot)For multiple backends, use the same pattern with each backend name:
dsctl bdb-lab db2ldif BACKEND_NAME /var/lib/dirsrv/slapd-bdb-lab/ldif/BACKEND_NAME-bdb.ldifReplace BACKEND_NAME with each backend reported by dsconf backend suffix list.
Import the matching LDIF file for each backend after you switch to LMDB:
dsctl bdb-lab ldif2db BACKEND_NAME /var/lib/dirsrv/slapd-bdb-lab/ldif/BACKEND_NAME-bdb.ldifStandalone example for backend userroot on instance bdb-lab:
Stop and export the backend:
dsctl bdb-lab stopdsctl bdb-lab db2ldif userroot /var/lib/dirsrv/slapd-bdb-lab/ldif/userroot-bdb.ldifThe export writes a complete LDIF snapshot for backend userroot.
Start the BDB instance temporarily so dsconf can update the configuration:
dsctl bdb-lab startSwitch the database implementation:
dsconf bdb-lab backend config set --db-lib mdbThe setting changes nsslapd-backend-implement from bdb to mdb.
Restart so the LMDB configuration becomes active:
dsctl bdb-lab restartSet the calculated map size:
dsconf bdb-lab backend config set --mdb-max-size 3GReplace 3G with the value you calculated for your database size.
Stop before the offline import:
dsctl bdb-lab stopImport the LDIF:
dsctl bdb-lab ldif2db userroot /var/lib/dirsrv/slapd-bdb-lab/ldif/userroot-bdb.ldifThe import rebuilds the userroot backend as LMDB from the exported LDIF.
Start and validate:
dsctl bdb-lab startdsctl bdb-lab healthcheckResolve any health-check errors before you return the instance to client traffic.
For a replicated supplier or hub, ordinary LDIF export and import alone is not enough when you must preserve replication state and changelog data. The upstream procedure uses replication-aware export and import plus separate changelog handling. Reinitializing from a healthy supplier is often safer than a hand-rolled manual conversion.
Recover from a failed migration
| Problem | Recommended action |
|---|---|
| Insufficient disk space | Stop, free space, and recover through the supported path without deleting the only copy of BDB or LDIF data |
| Export fails | Review backend and errors logs; do not switch nsslapd-backend-implement yet |
| Import fails | Preserve generated LDIF and migration logs for support |
| Instance does not start | Check dse.ldif, backend type, file permissions, and nsslapd-mdb-max-size |
| LMDB map is full | Increase nsslapd-mdb-max-size using the supported dsconf command |
| Migration was interrupted | Inspect the detected backend and migration files before rerunning |
| Validation fails before cleanup | Retain BDB files and restore from the verified BDB-era backup |
| Recovery method | Requires old BDB files? |
|---|---|
Change dse.ldif back to bdb |
Yes |
Run a fresh mdb2bdb conversion |
No, but write-capable BDB support and free disk space are required |
| Restore the original BDB native backup | Requires a compatible BDB instance |
| Reinitialize from another supplier | No native-backend compatibility requirement |
nsslapd-backend-implement back to bdb is lossless only while the converted instance has accepted no new LDAP or replicated changes. Once LMDB has accepted writes, the retained BDB files are stale. Switching directly back would discard those newer changes. Keep the instance out of write traffic until you either accept the LMDB result or complete the rollback. When newer changes must be preserved, use a fresh supported conversion, LDIF transfer, or replica reinitialization instead of merely editing dse.ldif.
Before dblib cleanup, a failed conversion can sometimes be rolled back to the untouched BDB files when no new writes occurred after conversion began. Stop the instance, preserve the current configuration, and edit dse.ldif only while Directory Server is offline:
dsctl bdb-lab stopCopy the current configuration before you edit it:
cp -a /etc/dirsrv/slapd-bdb-lab/dse.ldif /etc/dirsrv/slapd-bdb-lab/dse.ldif.before-bdb-rollbackChange nsslapd-backend-implement: mdb back to nsslapd-backend-implement: bdb in /etc/dirsrv/slapd-bdb-lab/dse.ldif, then restore SELinux context on the file:
restorecon -v /etc/dirsrv/slapd-bdb-lab/dse.ldifStart the instance on the original BDB files:
dsctl bdb-lab startConfirm the instance is healthy before you return it to service:
dsctl bdb-lab healthcheckDo not use this shortcut after cleanup, when BDB files are incomplete, or when the installed BDB package no longer matches the Directory Server build.
mdb2bdb exists only on builds that still ship Berkeley DB:
dsctl bdb-lab dblib mdb2bdb --helpusage: dsctl [-v] [-j] [instance] dblib mdb2bdb [-h] [--tmpdir TMPDIR]
options:
-v, --verbose Display verbose operation tracing during command execution
-j, --json Return result in JSON objectIf --help reports that mdb2bdb is unknown, the installed build no longer provides a BDB rollback path. The presence of the subcommand alone does not prove that the installed package provides a write-capable BDB backend on your platform.
Do not treat mdb2bdb as a permanent rollback strategy on releases that remove BDB entirely. It performs another full export-and-import conversion and can require substantial time and disk space. Plan recovery around verified backups and replica reinitialization instead. Run restore and reinitialization workflows from Restore a Replicated 389 Directory Server Safely when a converted replica cannot be returned to service.
What's next
After you complete this guide, continue with:
- Tune LMDB, Entry Cache and DN Cache in 389 Directory Server — size and tune the LMDB environment after conversion
- Update and Upgrade 389 Directory Server Safely — package updates after LMDB migration
- Restore a Replicated 389 Directory Server Safely — replica rebuild if conversion fails
- Export and Import 389 Directory Server Data with LDIF — manual LDIF fallback when automated conversion is unsuitable
Summary
- Detect the backend with
dsconfordse.ldifbefore you schedule downtime. - Choose automated
bdb2mdb, replica rebuild, or manual LDIF migration. - Verify disk space, create a verified native BDB backup, and record package versions.
- Run
dsctl INSTANCE dblib bdb2mdbon one instance at a time. - Validate LDAP, LDAPS, indexed searches, plug-ins, and replication.
- Convert replicas one at a time in replicated topologies; confirm
ds-replcheckbefore returning traffic. - Create the first LMDB-native backup, then run
dsctl INSTANCE dblib cleanupand remove any leftover migration LDIF files. - Use manual LDIF or replica reinitialization when automated conversion fails.
References
- How to migrate 389 Directory Server from Berkeley DB to LMDB (Port389)
- Red Hat Directory Server 12 — Migrating BDB to LMDB on an existing instance
- BerkeleyDB backend deprecation (Port389)
- 389 Directory Server 3.2.0 release notes
- Red Hat Enterprise Linux 10 — Identity Management adoption considerations
- Rocky Linux — DNF package manager
- Rocky Linux 10.2 CRB package repository

