---
title: "Relocating an installation to another drive, and moving or renaming a mailbox"
url: https://www.hmailserver.co.uk/topic/28244/relocating-an-installation-to-another-drive-and-moving-or-renaming-a-mailbox
author: "Progressiverobot"
published: 2026-09-27T19:26:13.731Z
updated: 2026-09-27T19:26:13.731Z
category: "Guides & tutorials"
tags: ["migration","windows","administration","database","diagnostics"]
site: hMailServer Community Forum
---

# Relocating an installation to another drive, and moving or renaming a mailbox

*Written for 6.3.4. hMailServer 6.3.7 (17 October 2026) bears on relocating a Windows installation to another drive. `hMailServer.exe /ProtectFolders`, which setup runs at every installation and upgrade, now hardens the program folder, `Bin` and `ControlPanel`: where hMailServer was installed in a folder that took its permissions from the root of a drive, any account that could sign in to the computer could replace the programs the service runs (CVE-2026-107571); the default folder under Program Files was never affected. The procedure below copies the tree and re-registers it without running setup, and a folder below a drive's root takes the permissions the root hands down, so an installation relocated there is hardened by the upgrade to 6.3.7, or on 6.3.7 by running `hMailServer.exe /ProtectFolders` as an administrator, not by the move (on 6.3.6 or earlier follow the icacls steps in `ServiceAccount.md`, since those versions' /ProtectFolders leaves the three program folders as they are); before upgrading an installation at a drive's root, follow the steps "Before upgrading an installation at a drive's root" in `ServiceAccount.md`. Where accounts that are not administrators could sign in to the computer while the installation was in such a folder, the release says to reinstall the programs into a new folder that only the administrators may change, not over the installation, with setup given the new folder by `/DIR=`: over an installation setup installs into the folder it finds, and a 32-bit installation's uninstall entry overrides `/DIR=` until it is taken away, which the "re-run the installer" repair below meets. See [the 6.3.7 announcement](/topic/28277). hMailServer 6.3.8 (2 November 2026) has setup make or harden the program folder, `Bin` and `ControlPanel` before it copies a file or runs a program of the installation. One of them that another account could change, as a folder below a drive's root can be, setup hardens and then refuses, with exit code 7, until Windows has restarted; and a folder or a link on the way to them, or a program, library, script or settings file in them, that another account than SYSTEM, the Administrators and TrustedInstaller controls, it refuses with exit code 7, naming the `icacls` that deals with it and a restart of Windows before setup runs again. On Windows 6.3.8 may also refuse, with HM7534 or HM7536, `TlsCaFile`, `PostgreSQLSslRootCert`, a TLS certificate or private key file, `OAuth2PublicKeyFile` or `AcmeCertificateDirectory` where its path holds characters outside ASCII, so give the new root, and the folders above it, an ASCII name. See [the 6.3.8 announcement](/topic/28278).*

This guide covers two different moves. The first is relocating a configured installation to another directory or drive on the same machine, for example from `C:\Program Files (x86)\hMailServer` to `C:\Program Files\hMailServer`. The second is renaming a mailbox or moving it to another domain, which is an operation of its own since 6.3.4. Moving to new hardware is a third thing, and [Moving to new hardware, and why Windows to Linux is a rebuild](/topic/28194) covers it. The one thing to know first: **relocating is not one change.** The installation path is recorded in the registry, in the service, in the COM registration, in `hMailServer.ini` and in a handful of database columns, and since 6.3.4 a `[Settings]` path edited in the file is ignored in favour of the value stored in the database.

The relocation runbook is written in Windows terms: the registry, the service and the COM registration. The documents used here give no separate procedure for a Linux installation. Installing somewhere new is a different, solved problem: `/DIR="<path>"` on the installer puts a fresh installation wherever you want.

### The good news first

The mail store itself is already relocatable. Message rows hold a bare `{guid}.eml` with no directory, and the path is rebuilt at every read against the data directory. Moving the data directory and pointing `DataFolder` at its new home moves every message with it. The exception is a database that predates hMailServer 5.4, where the column can hold a full path.

### Before you touch anything

1. **Take a backup and verify it restores** ([Backup and restore](/topic/28221)). Everything below is reversible only while the old tree and a good backup both exist.
2. **Ask the server whether its message rows are relative.** In the Control Panel, *Monitoring & troubleshooting → Diagnostics → Test message file locations*. If it reports `ERROR: Full paths are stored in the database`, the move is still possible, but converting the paths becomes mandatory rather than optional.
3. **Write down what you are about to strand.** The same Diagnostics page has an **Installation paths** section that lists the registry root, every `[Directories]` key and every path-shaped setting the running server holds, with the ones that do not exist marked. It changes nothing.

### The inventory

| Where | What | Repaired by |
|---|---|---|
| `Bin\hMailServer.ini`, `[Directories]` | `ProgramFolder`, `DataFolder`, `DatabaseFolder`, `LogFolder`, `TempFolder`, `EventFolder` | Editing the file |
| `Bin\hMailServer.ini`, `[Database]` | `PostgreSQLSslRootCert` and `TlsCaFile` | Editing the file. Leave the connection keys alone: they name a server, not a path |
| The settings store (`hm_inisettings`) | `ArchiveDir`, `AcmeCertificateDirectory`, `OAuth2PublicKeyFile`, `UpdateTrustRootsFile`, `UpdateLogPublicKeyFile`, and the certificate and private key files of the REST API, metrics and web services listeners | Storing the new value, not editing the file (since 6.3.4) |
| Registry, `HKLM\SOFTWARE\hMailServer` in the 32-bit view | `InstallLocation` | By hand |
| Registry: the service's `ImagePath`, `LocalServer32` (79 keys), `InprocServer32` (15), the TypeLib values | | `hMailServer.exe /Register` |
| Registry, `HKLM\...\Uninstall\hMailServer_is1` | `InstallLocation`, `UninstallString`, `DisplayIcon` | Nothing; re-run the installer |
| The database | Certificate and key files, DKIM key files, the client-certificate CA bundle, `backupdestination`, the ClamWin and custom scanner paths, rule actions | Each on its own page |

**What breaks when a key is left behind.** With a stale `DataFolder` the store appears empty. With a stale `LogFolder` logs are written to the old tree, silently. With a stale `EventFolder` event scripts are not found and events stop running.

**The 32-bit view is not optional.** The server reads `InstallLocation` through `KEY_WOW64_32KEY`, and the installer writes it there. Writing the 64-bit view changes nothing and looks like it worked.

### The procedure

1. **Stop the service**, and confirm it is stopped. Nothing here may run against a live server.
2. **Copy the tree. Copy, do not move**: the old tree is the rollback. Include `Bin\hMailServerApiKeys.ini` if it exists, since the REST API key store lives there and no installer manifest mentions it. Grant the service account access to the new tree as 6.3.8's [RelocatingAnInstallation.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.8/hmailserver/docs/RelocatingAnInstallation.md) does: a copy takes the permissions of the folder it lands in (under Program Files every user's Read on the new `Data`, `Logs`, `Temp`, `Database`, `Events` and `hMailServer.INI`) and not the old tree's entries for `NT SERVICE\hMailServer`, so the document makes the new root with the permissions setup gives a program folder before the copy, runs `hMailServer.exe /ProtectFolders` from the new `Bin` after step 5's `/Register`, and grants a service that runs as anything but LocalSystem its folders again with `/GrantServiceAccess`. A server that cannot write its log directory starts and then says nothing.
3. **Rewrite the file keys** in `<new root>\Bin\hMailServer.ini` whose value was under the old root: the `[Directories]` folders, and `[Database]` `PostgreSQLSslRootCert` and `TlsCaFile`, the second named beside the first by 6.3.8's document, since with `TlsMode=verify-full` a CA file left in the old tree stops the server reaching its database once that tree is deleted (HM7531). Nothing else, and not a folder that was outside the old tree and has not moved: a `DataFolder` pointed at an empty directory makes the store appear empty.
4. **Repoint the registry root**, from an elevated prompt: `reg add "HKLM\SOFTWARE\hMailServer" /v InstallLocation /t REG_SZ /d "<new root>" /reg:32 /f`. `/reg:32` is the whole of the point.
5. **Re-register the server**, from an elevated prompt, from the **new** `Bin`: `hMailServer.exe /Register`. It registers the path of the executable that runs it.
6. **Start it, and check what it read.** Read the application log, and since 6.3.4 the ERROR log too. Confirm that the Diagnostics page's **Installation paths** shows the new paths (6.3.8's document names it; the Control Panel has no *Settings → Directories* page), that your domains are listed, and that the log file you are reading is under the new log directory.
7. **Convert full message paths**, only if the diagnostic found any: run the **Data Directory Synchronizer**, in its import mode, on the old installation before step 2 copies anything, as step 0 of 6.3.8's [RelocatingAnInstallation.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.8/hmailserver/docs/RelocatingAnInstallation.md) has it, not against the new data directory after the move: it converts only a row whose full path is where the file is found, so after the move it would import every such message a second time, and its other mode would delete the copies. A hand-written `UPDATE hm_messages SET ...` is not a supported converter.
8. **Store the `[Settings]` paths and fix the database-borne paths** (both below).
9. **Verify before deleting anything**: send and receive a message; complete a TLS handshake on every port that has a certificate; run a backup to completion; run an event script, if you use them; check the log directory is being written.
10. **Keep the old tree**, unreachable by the service, for at least one full backup cycle. Do not make it unreachable until the `[Settings]` paths are stored and a reinitialise has picked up the new certificate and ACME paths.

**The failure this prevents.** A server whose anchors are stale reports `Running` and serves an empty configuration. That failure is silent.

### The `[Settings]` paths: 6.3.3 and earlier, and since 6.3.4

On 6.3.3 and earlier these are `[Settings]` keys of `hMailServer.ini` like any other, and editing the file moves them. **Since 6.3.4 it does not**: the stored value is used, the edit is named in the error log as `HM5804`, and, where the service can write the file, the line is put back to the old path. [RelocatingAnInstallation.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/RelocatingAnInstallation.md) and the wiki page between them give three ways to store the new values. The first is the document's own, and the one to use:

| When | How | Where it is described |
|---|---|---|
| After the moved server is running | In the Control Panel under **Settings**, with `Settings.SetIniSetting` over COM, `PUT /api/v1/settings/ini/{name}`, or `hmctl ini set <name> <value>` | [RelocatingAnInstallation.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/RelocatingAnInstallation.md), step 9, and the wiki |
| Before stopping the old server | The same four ways, as the last thing before the service is stopped. A save applies `ArchiveDir`, `OAuth2PublicKeyFile`, `UpdateTrustRootsFile` and `UpdateLogPublicKeyFile` at once, not at the next start as the wiki page has it, so the running old server turns to a tree not yet copied: archiving stops, and token validation and update verification refuse. The database then holds the new paths, so going back to the old tree means storing the old values again | The wiki, corrected by [SettingsApply.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/SettingsApply.md) |
| At the first start, if the service is already stopped | A `[SettingsOverride]` section in the new `hMailServer.ini`, named in the error log as HM5807; then store the same values and remove the section before the next restart | The wiki |

A save applies every one of these paths at once except the listeners' certificate paths and the ACME certificate directory, which are bound when the servers start and wait for a reinitialise (**Apply now**, or `POST /api/v1/server/reinitialize`). Until then the server runs on the old paths, which still resolve because the tree was copied rather than moved. `PasswordPepper` is the exception to all of this: it lives in the file only, is not a path, and comes across with the copied file.

### The database-borne paths

- **SSL certificates.** Since 6.3.7 the Control Panel's SSL certificates page has **Edit…**, which changes a certificate's name and files and keeps its id, so every port that presents it keeps it and reads the new files at the next reinitialise; deleting a certificate and adding it again, as the document had it until 6.3.8, leaves each port that presented it with none, and such a port does not start (HM5113). It can also be set over COM.
- **DKIM keys.** *Domain → DKIM*, the primary and, if used, the secondary. A domain whose key rotation manages its keys refuses that edit.
- **Client-certificate CA bundle**, per port. A port set to require a client certificate refuses every client when its bundle cannot be loaded.
- **Archive index.** `hm_archiveindex.archivepath` is matched on the exact string by retention, legal hold and the address eraser. Do not bulk-rewrite it. If the archive directory moved, move the archive back, or accept that the rows written before the move point at the old location; there is no supported converter for this column.

### What stays broken, and why

- **Add/Remove Programs** still points at the old `unins000.exe`. Do not edit `unins000.dat`. The supported repair is to re-run the installer at the new root.
- **Start-menu shortcuts** hold absolute targets and nothing repairs them.
- **Message content.** The old path appears inside messages the server itself wrote, such as a delivery report. Never rewrite message content.

### Renaming a mailbox, or moving it to another domain

New in 6.3.4 (schema 6056, whose table `hm_mailboxmoves` is the move's journal). `new_address` carries the domain, so renaming and moving are the same operation: `ann@example.com` to `anne@example.com` is a rename, `ann@example.com` to `ann@example.net` is a move. **A move keeps the account's row**, so everything keyed on the account id follows without being touched: rules, folders with their subscriptions and access-control entries, application passwords, the second factor, contacts, calendars and the role assignment. Copying the mail into a second account loses all of it.

| Interface | How |
|---|---|
| Control Deck | The **Move or rename** card in the account editor |
| `hmctl` | `hmctl mailbox status ann@example.com`, then `hmctl mailbox move ann@example.com ann@example.net` |
| REST | `POST /api/v1/accounts/ann%40example.com/move` with `{"new_address": "ann@example.net", "keep_alias": true}`; `GET` on the same path says whether anything holds the mailbox |
| PowerShell | `Move-HmMailbox -Address ann@example.com -NewAddress ann@example.net` |
| Control Panel (Windows) | **Move or rename…** on the account's General tab |
| COM (Windows) | `Account.MoveTo(NewAddress, KeepOldAddressAsAlias)` or `Utilities.MoveMailbox(Address, NewAddress, KeepOldAddressAsAlias)` |

**The old address is kept as an alias by default**, pointing at the new address. Turn it off (`keep_alias` false, `--drop-alias`) only when the address is to stop working: mail to it is then refused at `RCPT TO`.

**What moves:** the message store directory `<data>/<domain>/<local part>`; the Sieve tree; aliases in any domain that point at the account; distribution list memberships; recipients of mail still in the delivery queue; and quarantined mail, up to a ceiling of 200,000 rows.

**What does not move, on purpose.** The archive and the message trace stay under the old address, as a record of the past. Erasure works by address, so erasing the new address will not reach the archive written under the old one: erase both ([Compliance: personal data and erasure](/topic/28242)). The domains a role reaches are not rewritten either, so check a role after a cross-domain move ([Administrator roles end to end](/topic/28237)).

**What is refused, before the first byte is moved:**

- a domain this server does not hold, or one that is not active;
- a destination domain at its maximum number of accounts, or that would exceed its maximum total size;
- an account, an alias or a distribution list already at the new address;
- a mailbox encrypted at rest moving to another domain (`409`); a rename inside the domain is not refused;
- an installation whose message file names are still full paths;
- a credential that may not administer accounts in both domains;
- a mailbox in use.

**In use** means a POP3 session, or an IMAP session with one of the account's folders selected. What is not counted: an IMAP session that has selected nothing, a webmail request in flight, a ManageSieve session and an SMTP delivery to the mailbox in flight. A message that arrives during the copy is written under the old directory, and the old directory is swept once afterwards; anything that could not be carried is `HM6948`. That is why a move of a large busy mailbox belongs out of hours.

### When a move fails or is interrupted

There is no transaction across a filesystem and four database backends, so the order is chosen to make each step undoable: the store, then the account row, then the references, then the alias. A journal row is opened before the first step and closed after the last, and an interrupted move is said once per start as `HM6947` in the application log, naming both addresses and the stage it stopped at.

| Stage | What it means |
|---|---|
| `started` | Nothing has been changed |
| `moving the store` | The copy was under way; look at both directories. The database has not been touched |
| `store moved` | The directories are at the new address. While the account row says the old one, the account authenticates and its mail is unreadable |
| `account written` | The store and the account row agree; the references have not all been rewritten |
| `references rewritten` | Everything but the alias |
| `complete` | The move finished |
| `rolled back` | A step failed and everything before it was put back |
| `rollback failed` | Something could not be put back; `HM6940` is in the application log |

To finish a move interrupted at `moving the store` or `store moved`, ask for the move again, naming the address the directories now have. Read the journal with `hmctl mailbox status` or `GET /api/v1/accounts/<address>/move`. The journal is not in the backup.

| Code | Meaning |
|---|---|
| `HM6941` | The move succeeded but the alias for the old address could not be created |
| `HM6942` | Aliases pointing at the account could not be re-pointed |
| `HM6943` | Distribution list memberships could not be moved |
| `HM6944` | Messages in the delivery queue still name the old address |
| `HM6945` | Quarantined messages still name the old address |
| `HM6946` | The move could not be journalled. It still happened, and is on the audit trail |

**Who may.** `manage_accounts`, in both domains. The server administrator and a domain administrator of both domains have it; the help-desk role and the auditor do not. `view_accounts` is enough to read the journal. A move is one entry on the audit trail: object type `account`, action `moved`.

### What it does not do

- The relocation runbook does not repair the uninstall entry or the shortcuts, and it has no converter for the archive index.
- A mailbox move does not wait for a delivery in flight; nothing in the server records one.
- Setting `Account.Address` and saving goes through the same implementation, but leaves no alias, does not refuse while the mailbox is in use, and cannot cross domains.
- A domain rename (`Domain.Name` and `Save()`) is a different thing again, and keeps the path it has always taken.

### Where to read more

- Wiki: [Relocating an Installation](https://gitlab.com/hmailserver/hmailserver/-/wikis/Relocating-an-Installation).
- Documents: [RelocatingAnInstallation.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/RelocatingAnInstallation.md) and [MailboxMove.md](https://gitlab.com/hmailserver/hmailserver/-/blob/v6.3.4/hmailserver/docs/MailboxMove.md).
- The public documentation: [33.1, the installation on disk](https://www.progressiverobot.com/hmailserver-documentation/#331-the-installation-on-disk).
- On this forum: [Moving to new hardware, and why Windows to Linux is a rebuild](/topic/28194), [Upgrading to 6.3.4](/topic/28193), and how the settings store works and when a save takes effect in [Settings: what is not stock, when a save takes effect, and the three levels](/topic/28222).
