Safely sync or back up Dovecot mailboxes with doveadm
You will finish with a checked command for copying one Dovecot mailbox set to another location, plus a safe choice between two-way synchronisation and a one-way backup. The examples match dovecot-core version 1:2.3.21+dfsg1-2ubuntu6.5 installed on this machine. Allow about fifteen minutes for a dry run and a further ten minutes if you are planning a migration.
The route
Jump straight to the step you need, or tick off Done means at the end.
- 1. Choose the operation before choosing the command
- 2. Check the local installation and account
- 3. Run a two-way remote synchronisation
- 4. Create a one-way backup or convert storage
- 5. Make incremental runs safer and more predictable
- 6. Use migration filters only with an explicit scope
- 7. Know the version boundary
You need a working Dovecot configuration, access to the mailbox storage, and a destination that the Dovecot process can read and write. These commands can change or delete mail at the destination. Take a separate backup first, stop competing mailbox maintenance, and test with one non-critical account before using a production account. Use sudo only where the mailbox permissions require it.
1. Choose the operation before choosing the command
The names are easy to confuse. doveadm sync is two-way: changes from both sides are merged and the mailboxes should end up equivalent. doveadm backup is one-way: the destination is made to match the source, so changes already present only at the destination can be removed. The older name dsync refers to the same feature and is installed here as a compatibility command.
Use sync when both mailboxes are active and changes on either side must survive. Use backup when the destination is a disposable replica or backup. Do not use backup against a mailbox that contains unique mail until you have confirmed that the source is complete.
Checkpoint: write down the source and destination, and decide which side is allowed to change. If that sentence is not clear, do not run the command.
2. Check the local installation and account
Confirm the command path and the package version without changing mail:
$ command -v doveadm
/usr/bin/doveadm
$ dpkg-query -W -f='${Package} ${Version}\n' dovecot-core
dovecot-core 1:2.3.21+dfsg1-2ubuntu6.5
Run the operation as the account that owns the storage, or use the service account and its normal configuration. When you pass -u, Dovecot may use the auth process for a userdb lookup. Without -u, -A, or -F, the command uses the currently logged-in user's environment. For several users, -F FILE reads one username per line; -A obtains users from the userdb and needs a correctly configured iteration query.
Checkpoint: inspect the effective configuration before proceeding:
$ sudo doveconf -n
Pay particular attention to mail_location, userdb settings, and any replica destination. The sync operation can run without Dovecot server processes, except that a -u userdb lookup may contact the auth process.
3. Run a two-way remote synchronisation
A remote destination normally uses Dovecot's dsync_remote_cmd setting, commonly an SSH command. Replace both placeholders with real values and keep the username explicit:
$ sudo doveadm sync -u [email protected] remote:replica.example.net
The destination syntax is not a general URL. The remote: form uses the configured remote command. Other supported forms include tcp:HOST[:PORT], tcps:HOST[:PORT], a local mailbox location such as maildir:~/Maildir, and a local command connected to a dsync server.
For a more complex SSH invocation, pass the command that starts the remote protocol:
$ sudo doveadm sync -u [email protected] \
ssh -i /path/to/replica-key \
[email protected] doveadm dsync-server -u [email protected]
The command writes errors to standard error. A status of 0 means the synchronisation completed perfectly. A status of 2 means it completed without a hard error, but some changes could not be applied, often because a mailbox changed during the run. Run it again and require status 0 before calling a final migration complete:
$ status=$?
$ printf 'doveadm status: %s\n' "$status"
doveadm status: 0
That capture must immediately follow doveadm. Status 1 or a value greater than 2 indicates failure. Read the error before retrying; a repeated failure can indicate a permission, connection, configuration, or storage problem.
4. Create a one-way backup or convert storage
For a destination that should mirror the source, use backup. This example copies the configured mailbox format into a Maildir destination:
$ sudo doveadm backup -u [email protected] maildir:/srv/mail-backups/USER/Maildir
$ status=$?
$ printf 'backup status: %s\n' "$status"
Check the destination with the storage tools appropriate to your format, and keep the original until you have inspected several folders and messages. If the destination was the wrong path, stop using it immediately and restore it from the separate backup. There is no general undo operation for data removed by a one-way backup.
For a format conversion, the destination can be a local location while mail_location remains the configured source format. The local manual gives the example doveadm sync maildir:~/Maildir when the configured location is mdbox. For a live conversion, run an initial sync, run it again to catch mail received during the first pass, change the per-user location, end existing IMAP and POP3 sessions that still use the old location, then run a final sync. Treat the location change and session termination as a maintenance operation, not as part of a casual test.
5. Make incremental runs safer and more predictable
The default fast algorithm checks mailbox metadata and normally avoids scanning unchanged mailboxes. Use -f for a full synchronisation when you need every mailbox and message checked. It is slower, not a repair for an unknown destination.
For repeated incremental runs, -s enables stateful synchronisation. Start with an empty state, capture the new state printed on standard output, and pass that exact value to the next run:
$ state=$(sudo doveadm sync -u [email protected] -s '' remote:replica.example.net)
$ printf 'new sync state: %s\n' "$state"
$ sudo doveadm sync -u [email protected] -s "$state" remote:replica.example.net
Do not edit, wrap, or casually log the state string. Preserve it with the mailbox job and replace it only with the state from a successful subsequent run. If the state or either mailbox is corrupted, discard the state and perform a fresh synchronisation as the local manual recommends.
Use -l SECONDS when more than one job might run for the same user. It waits for the per-user dsync lock and then gives up. Use -m MAILBOX for a single mailbox, -n NAMESPACE for a namespace, or repeated -x MASK options to exclude mailboxes. These narrow the operation; they do not make an unsafe destination safe.
6. Use migration filters only with an explicit scope
The options -t and -e limit messages by received timestamp. -I SIZE skips messages larger than the specified size. -O FLAG synchronises only messages carrying a flag; prefix the flag with a hyphen to select messages without it. These filters intentionally produce a partial mailbox, so do not mistake a successful exit for a complete migration.
-R reverses the normal flow, pulling from the remote side into local storage. Treat it as a destructive-direction switch: verify the command with a test user and re-read the destination before running it on real mail. -P runs a purge on the remote destination after synchronisation and should be reserved for a documented retention workflow.
7. Know the version boundary
This host is on Dovecot 2.3.21. Current Dovecot documentation describes the same sync and backup concepts, but Dovecot 2.4 removed the standalone dsync command symlink. For portable procedures, write doveadm sync or doveadm backup explicitly and do not depend on dsync being present. Re-check the installed manpage when moving the procedure to a different major version.
Done means
- You chose two-way
syncor one-waybackupdeliberately. - The source, destination, account, permissions, and Dovecot configuration were checked.
- A test run completed with exit status
0, not merely status2. - You inspected the destination and retained a recovery copy before deleting or replacing anything.
- Any saved
-sstate belongs to the correct mailbox pair and was captured from a successful run.