Skip to content
hMailServer 6.3.8 is the current release, signed 2 November 2026. Windows and Linux, and an in-place upgrade from 5.3 or later, but for the original hMailServer's 5.7.Download 6.3.8 Documentation FAQ
  • 0 Votes
    1 Posts
    176 Views
    ProgressiverobotP
    Written for 6.3.4. hMailServer 6.3.7 (17 October 2026), a security release, keeps the schema at 6108: an upgrade from 6.3.6 changes no table, from 6.3.5 or older the upgrade runs 6.3.6's three one-way steps to 6108, and from 6.3.3 or older 6.3.4's steps come first. On MySQL and MariaDB an insert that forgives a duplicate key now forgives that alone and any other failure is reported (HM5032), where it was taken as done with no row written, and a lost connection is reconnected and the statement run again, so the statement after a database restart, a failover or wait_timeout no longer fails; an error log that was quiet may now name failures that were hidden. See the 6.3.7 announcement. hMailServer 6.3.8 (2 November 2026), a security release, adds no schema step, so an upgrade from 6.3.6 or 6.3.7 changes no table. With TlsMode=verify-full on MySQL and MariaDB it checks the database server's certificate against the CA file TlsCaFile names, where in 6.3.4 to 6.3.7 a name holding a character outside ASCII reached the client as no CA file (work item 112); and through MariaDB Connector/C it refuses verify-full without TlsCaFile to a database server on this machine (127.0.0.1, ::1, localhost, an empty Server= or a Server= list that holds one) with HM7535, where Connector/C 3.4.1 and later checked neither that certificate's issuer nor its name (work item 113): before upgrading, name in TlsCaFile a CA that issues nothing but the database's certificates, the one that issued its certificate, or set TlsMode=require. The distribution's client should be MariaDB Connector/C 3.4.11 or later; where it is older and not patched, name the CA in TlsCaFile. On a server that ran under a LANG that is not UTF-8, rename a TlsCaFile named outside ASCII to its UTF-8 name before upgrading. The container image now carries MariaDB's client, so a container told MySQL reaches MariaDB. See the 6.3.8 announcement. A Linux server keeps its accounts, domains, settings and message metadata in PostgreSQL or in MySQL/MariaDB, and in nothing else. There is no built-in database on Linux, hmailserver --create-database refuses SQL Server and SQL Server Compact by name, and SQL Server is refused on Linux as HM6390, because ADO is Windows. This topic covers the choice between the two, the client library each needs, the [Database] section, each backend's set-up step by step, TLS to the database, and what the schema upgrade asks of MySQL and MariaDB. The one thing to know first: since 6.3.4 every table on MySQL and MariaDB is utf8mb4, which needs MySQL 5.7.9 or MariaDB 10.2.2, or later. On an older server the create script stops at its first table, and an upgrade from 6.3.3 stops at its first step, 6040 to 6041, with error 1071, having changed nothing. Check the version before anything else. The first install as a whole is First install on Linux. Choosing between the two PostgreSQL MySQL / MariaDB [Database] Type PostgreSQL MySQL (MariaDB is MySQL) Port 5432 3306 Proven on PostgreSQL 18 for the first Linux proof; PostgreSQL 17 in the TLS lab MySQL 5.7.44 and 8.4.11, MariaDB 10.6.28, 11.4.13 and 11.8.9, on 25 September 2026 Client library libpq, pulled in by the package's own dependencies libmariadb.so.3, opened at run time, installed by you Upgrade steps that ship every step from 5001 onwards every step, back to schema 0 Transactions DDL is transactional, so a failed schema step rolls back cleanly used only if every table reports InnoDB at connect time TLS with nothing set libpq's own prefer prefer since 6.3.4; never encrypted through MariaDB Connector/C before MigratingDatabaseBackend.md calls PostgreSQL the best-behaved backend in this codebase, and gives "you already run it" as the reason for MySQL or MariaDB. Both are proven live on Linux: schema created, account made, message delivered and read back. That the PostgreSQL steps begin at 5001 is not a gap, because PostgreSQL was not a backend before hMailServer 5. Moving between the two later is not an upgrade, and the chain does not do it: it is a new installation against the new backend and a migration. The client library to install The .deb and the .rpm declare their library dependencies automatically (dpkg-shlibdeps for the .deb, rpm's own auto-requires), so libpq is pulled in with the package. MySQL and MariaDB are different: the server opens libmariadb.so.3 at run time rather than linking it, so the wiki tells you to install the client library yourself. Distribution Package Debian, Ubuntu libmariadb3 Fedora, RHEL mariadb-connector-c Arch mariadb-libs Where there is no libmariadb, the server loads Oracle's libmysqlclient. Only Oracle's 8.x client is given TLS options: with any other, require and verify-full are refused with the version it reports, rather than claimed. Oracle's libmysqlclient.so.24, MySQL 8.4's client as Ubuntu 26.04 packages it, is not among the names the Linux server loads. On Windows the client is bundled, as libmysql.dll; it is the same MariaDB Connector/C: 3.4.9 in the x64 installers of 6.2.3 to 6.3.6, and 3.4.11 in 6.3.7's, built from MariaDB's source, with seven authentication plugins where 6.3.6's had nine. The Linux server loads the distribution's libmariadb.so.3, which the distribution patches. The [Database] section The file is root's, so edit it with sudoedit /etc/hmailserver/hMailServer.ini. Key What to write Type PostgreSQL or MySQL Server, Database, Username, Password Where the database is and who the server connects as. The Linux package's template reads a password typed with Passwordencryption=0 as plain text Port Written out, 5432 or 3306: it goes into the connection string as it stands, and there is no useful default TlsMode, TlsCaFile Since 6.3.4, optional (below) UpgradeOnStart Since 6.3.4: 1 lets the service bring its own schema forward as it starts. Off by default, and not needed on a package installation, whose post-install step runs the upgrade NumberOfConnections The pool that deliveries, sign-ins and the rest share; five as shipped These keys are read at the service's start, and are in the file rather than the settings store because they say how the store is reached. sudo -u hmailserver hmailserver --check-config prints the database type it made of what you wrote, without opening the database; Database type: 0 means the Type key did not take. PostgreSQL, step by step Create the role. With --createdb the server creates the database itself in step 3: sudo -u postgres createuser --pwprompt --createdb hmailserver If you would rather the service role could not create databases, which the wiki calls the tidier policy, leave the flag off and create the database yourself: sudo -u postgres createuser --pwprompt hmailserver sudo -u postgres createdb --owner hmailserver hmailserver Write [Database]: Type=PostgreSQL, the server, the database, the role, its password, and Port=5432. Create the schema, as the service user: sudo -u hmailserver hmailserver --create-database If TLS is to be required, that is the database server's to say: ssl=on and a certificate in postgresql.conf, and hostssl lines in pg_hba.conf. MySQL or MariaDB, step by step Check the version against the floor. The reason is key size: a key over a varchar(255), an account's address or a folder's name, is 1020 bytes at four bytes a character, more than an InnoDB key part may be in the older COMPACT rows (767 bytes). MySQL 5.7.9 and MariaDB 10.2.2 are the first releases whose InnoDB, as it ships, takes a key part of up to 3072 bytes and makes its tables DYNAMIC. On a MySQL 5.7 set up as 5.6 shipped, the error is 1071, "Specified key was too long; max key length is 767 bytes". Install the client library from the table above. Create the database, or let the verb create it, and give the account the server connects with every privilege on it: CREATE DATABASE hmailserver CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; GRANT ALL PRIVILEGES ON hmailserver.* TO 'hmailserver'@'%'; Every table names its own character set, so a database made with another default still works. But the upgrade steps create, alter and index tables, and the 6102 step also changes the database's own default character set, which needs the ALTER privilege on the database itself; ALL PRIVILEGES ON <database>.* has it. A database the server creates itself is made utf8mb4 already. Make sure every table ends up InnoDB: the server issues transactions only if they all report it at connect time, and silently does not if any does not. Write [Database]: Type=MySQL, the server, Port=3306, the database, the account and its password. Create the schema: sudo -u hmailserver hmailserver --create-database. Why utf8mb4. MySQL's utf8 is utf8mb3, three bytes a character, so nothing outside the Basic Multilingual Plane fits in it: no emoji. Before schema 6102 such a character in a contact, a folder or a signature was refused with error 1366 under strict mode, and made a question mark where strict mode is off. utf8mb4_general_ci is the twin of utf8_general_ci, the collation the tables had, so an address or a name compares as it did. What it does not do is tell characters outside the Basic Multilingual Plane apart: two address books of one account whose names differ only in an emoji are one name to its unique index. What --create-database does The package installs the server enabled and stopped, on purpose: there is no database yet, and the schema is made afterwards with this verb. If the database is not there, the verb connects to the server [Database] names with no database selected, creates it in the backend's own dialect and reconnects; if it is there and empty, it uses it. Either way it then runs the create script for the backend's type, which is what DBSetupQuick does over COM on Windows, and a database 6.3.4 creates is stamped 6104. Since 6.3.4, says the wiki's Installing on Linux, a database that already holds this build's schema, or an older one, is left as it is with exit 0, and a newer one exits 1; 6.3.3 refused any database that already held a schema. The documentation page (35.4, 35.7) still says a schema is refused, exit 1: test it on a scratch database first. Two things follow a create, both since 6.3.4. The database, an empty one you created first included, is marked for a new installation's secure defaults, which the systemd unit's first start applies if it comes within a day; a database that already held a schema is not marked. And run as the service user on a package installation, the verb cannot write the root-owned configuration, so it makes no stored-secrets key and says what to run instead, sudo hmailserver --create-stored-secrets-key. Export that key and keep the file with the database dumps, apart from them: a dump restored without it brings back every second factor and [Settings] secret unopenable. Both are covered in full in Hardening a public mail server. TLS to the database (since 6.3.4) Before 6.3.4 the connection to MySQL and MariaDB through MariaDB Connector/C, the client Ubuntu packages, was never encrypted, and a database account made with REQUIRE SSL refused the server. Since 6.3.4 two [Database] keys choose the behaviour on every backend (on PostgreSQL the older PostgreSQLSslMode and PostgreSQLSslRootCert win when they are set), and are read at the service's start: TlsMode, one of disable, prefer, require or verify-full (empty is prefer: TLS when the server offers it, the certificate unchecked), and TlsCaFile, a PEM file of CA certificates that verify-full checks against: [Database] TlsMode=verify-full TlsCaFile=/etc/hmailserver/db-ca.pem Only verify-full checks the certificate, and only it protects against someone on the path who can alter the traffic. On Linux, MySQL and MariaDB take the CA file or the system's store, /etc/ssl/certs, and which client library is loaded matters: of Oracle's clients only 8.x is given TLS options (above). On PostgreSQL, verify-full with no TlsCaFile is sslrootcert=system on Linux, with libpq 16 and later. What each mode does, the refusals (HM7530, HM7531), what each backend did before 6.3.4 and does now, and what is thinner than it could be are in Choosing a database, creating it, encrypting the link. The server cannot make the database server refuse plaintext: that is REQUIRE SSL on the MySQL account, or hostssl lines only in pg_hba.conf. Try it before the service is given it. --check-database makes one connection with the TLS settings in the configuration, prints the result, and exits 0 connected, 1 not, 2 not configured. It changes nothing, so it runs beside a running service: $ sudo -u hmailserver hmailserver --check-database Configuration: /etc/hmailserver/hMailServer.ini Database: MySQL/MariaDB on 192.0.2.20:3306, database hmailserver, as hmailserver TLS: TlsMode verify-full, the certificate checked against /etc/hmailserver/db-ca.pem Connected. MySQL/MariaDB: encrypted with TLS (TLS_AES_256_GCM_SHA384), the server's certificate checked (TlsMode verify-full) The application log says the same of the running service's connection, in a line that begins Database connection:. In a container (no image of 6.3.4 is published, so one you build from the .deb) the entrypoint writes [Database] from the environment at every start, so there HM_DB_TLS_MODE and HM_DB_TLS_CA set these, not a line in the file. Upgrading the schema, and the floor On a package upgrade the maintainer scripts run hmailserver --upgrade-database as the service user, only when a database is configured, then try-restart the service if it was running. A failure of the schema upgrade is reported and does not fail the package, so read what it printed. The verb is safe to run by hand, and says "nothing to do" when done: sudo -u hmailserver hmailserver --upgrade-database The chain is applied one step at a time from whatever version the database reports, which select value from hm_dbversion answers. A database from a newer build is refused, and a server refuses to start on a database that is too old or too new for it. Take the dump first, with pg_dump or mysqldump, and the data directory with it: the upgrade is one-way, and rolling back is restoring that dump and reinstalling the older package (Upgrading from 5.x, 6.2 or 6.3: rolling back). From 6.3.3 to 6.3.4 the schema moves from 6040 to 6104 in 64 steps. On PostgreSQL step 6102 only moves the version. On MySQL and MariaDB it converts every table to utf8mb4 under utf8mb4_general_ci, InnoDB and ROW_FORMAT=DYNAMIC: What Detail Time and disk It takes as long as copying the database. Each table is rebuilt in turn, and hm_messages, hm_message_metadata, hm_messageindexterms, hm_messagerecipients and hm_audit take the time: one to five seconds on an empty schema, minutes or more on a large installation. Have free disk space of the order of the largest table The floor, error 1071 Steps 6041, 6101 and 6102 each open with a statement that needs a long key; 6041 and 6101 make and drop a probe table, hm_upgradeprobe. On a server older than MySQL 5.7.9 or MariaDB 10.2.2 the upgrade stops at 6040 to 6041 with error 1071, and nothing has been changed. Upgrade the database server, then the schema The privilege, error 1044 The step changes the database's default character set, which needs ALTER on the database itself, not only on its tables A duplicate, error 1062 Two rows that the old collation told apart and the new one does not, under one unique index, stop the step; the error names the index and the value. The wiki's examples are straße and strase in one address book on MariaDB 11.8, and on MySQL 8.4 two names that differ only in an emoji. Rename or remove one and run the upgrade again: every statement of the step can run twice Afterwards A text column may read mediumtext, and a mediumtext one longtext. The server reads both alike Until 26 September 2026 steps 6041 and 6101 made their first tables before the index that failed, so an unreleased build from before that day could leave a database half done at 6040 or 6100. No upgrade path repairs that; Upgrading.md gives the DROP TABLE statements that do. Two nodes on one database are serialised step by step if they start together: on PostgreSQL by the version row, which each step locks for the length of its transaction, and on MySQL and MariaDB by a named lock, GET_LOCK('hmailserver_schema_upgrade'), held until the step is over and waited on for up to four hours. A server that refuses GET_LOCK altogether, MariaDB Galera with wsrep on, still upgrades with the row lock alone, and the output says so for each step: there, upgrade from one node at a time. Where to read more Installing on Linux and Before You Install, section 3.5, on the wiki. DatabaseTls.md, with the Linux lab run of 25 September 2026 line by line; Upgrading.md for the 6102 step and the repair of a half-done one; MigratingDatabaseBackend.md for why utf8mb4. The documentation page: 3.5 A database, 35.4 Creating the database and 35.13 Upgrading and rollback. On this forum: First install on Linux, Upgrading to 6.3.4 and Moving to new hardware; choosing a database and encrypting the link for TLS on every backend, and the hmailserver command line on Linux for the other verbs.
  • 0 Votes
    1 Posts
    157 Views
    ProgressiverobotP
    Written for 6.3.4. hMailServer 6.3.7 (17 October 2026) adds no schema step (6108, as 6.3.6). Its x64 installer's MySQL and MariaDB client is MariaDB Connector/C 3.4.11, built from MariaDB's source, in place of the 3.4.9 that 6.2.3 to 6.3.6 carried (CVE-2026-107819), with seven authentication plugins where 6.3.6's had nine: a database account that signs in with MySQL Enterprise's Windows authentication can no longer sign in, and the server then cannot open its database; the ARM64 installer carries no MySQL or MariaDB client. On MySQL, MariaDB, SQL Server and SQL Server Compact an insert that forgives a duplicate key now forgives that alone and any other failure is reported (HM5032), and on MySQL and MariaDB a lost connection is reconnected and the statement run again, so an error log that was quiet may now name failures that were hidden. See the 6.3.7 announcement. hMailServer 6.3.8 (2 November 2026), a security release, adds no schema step either. Through MariaDB Connector/C, the client the Windows installer bundles and the Linux server loads, TlsMode=verify-full without TlsCaFile to a MySQL or MariaDB server on this machine (by a loopback address, localhost, a Unix socket or a named pipe, or through a Server= list that holds one) is refused with HM7535, since in 6.3.4 to 6.3.7, with Connector/C 3.4.1 or later, neither the certificate's issuer nor its name was checked there: before upgrading, name in TlsCaFile a CA that issues nothing but the database's certificates, the one that issued its certificate, or set TlsMode=require. A TlsCaFile whose name holds a character outside ASCII, which in 6.3.4 to 6.3.7 could reach the client as no CA file at all, is now handed to it as named; on Windows a TlsCaFile or PostgreSQLSslRootCert name the client cannot be handed as named is refused with HM7534, so give the file, and the folders above it, an ASCII name; and on Linux, where the distribution's client is older than Connector/C 3.4.11 and not patched, name the CA in TlsCaFile. See the 6.3.8 announcement. This topic covers the four databases hMailServer 6.3.4 can keep its data in, what each needs before the schema can be made, how the connection to the database server is encrypted since 6.3.4, and how to move an installation off the built-in engine. The one thing to know first: on MySQL and MariaDB, 6.3.4 needs MySQL 5.7.9 or MariaDB 10.2.2 or later, because since schema 6102 every table is utf8mb4. On an older server the create script stops at its first table, and an upgrade from 6.3.3 stops at its first step, 6040 to 6041, with error 1071 and nothing changed. What the database holds, and what it does not hMailServer stores accounts, domains, message metadata and settings in the database. The message bodies are files on disk, one per message, at <DataFolder>\<domain>\<local part>\<xx>\{guid}.eml, so the database stays small relative to Data\. Since 6.3.4 the database is also the settings store: the [Settings] keys of hMailServer.ini are rows from schema 6042, the file's section is the server's copy, and a line edited there for a key the database holds is named in the error log as HM5804 and does not take effect. Where the service may write the file the line is put back; where it may not (a new Windows installation under NT SERVICE\hMailServer, a Linux package installation) the copy is not refreshed, the edited line stays, and the database's value is used. The [Database] section itself stays in the file, because it says how the store is reached. The four choices Database [Database] Type What is bundled What you must have first Built-in (SQL Server Compact 4.0 SP1) MSSQLCE SSCERuntime_x64-ENU.msi, installed by setup Nothing. This is the default MySQL / MariaDB MYSQL MariaDB Connector/C 3.4.9 as Bin\libmysql.dll (3.4.11 since 6.3.7, with seven authentication plugins where 6.3.6's had nine) A reachable server, MySQL 5.7.9 or MariaDB 10.2.2 or later, an empty database, and a user that may create tables Microsoft SQL Server MSSQL Nothing; the OS's own data stack The same, including Express edition PostgreSQL PostgreSQL libpq from PostgreSQL 18.3 The same On Linux there is no built-in database: a Linux server keeps its data in PostgreSQL or MySQL/MariaDB, and hmailserver --create-database refuses SQL Server and SQL Server Compact by name. For MySQL or MariaDB install the client library yourself, because the server opens libmariadb.so.3 at run time: libmariadb3 on Debian and Ubuntu, mariadb-connector-c on Fedora and RHEL. Databases on Linux has the steps for each backend, and First install on Linux the order of the whole first install. Two things about the built-in engine. It runs on a single database connection: NumberOfConnections is forced to 1 for MSSQLCE. And Microsoft has withdrawn the SQL Server Compact download; the copy in installation/SQLCE/ is the archive of record, and it still installs. MigratingDatabaseBackend.md calls it "the one real dependency liability in this tree". For anything up to a few dozen mailboxes it is adequate, and the last section of this topic is the way off it. How the four behave differently MS SQL Server PostgreSQL MySQL / MariaDB SQL Server Compact DDL in a transaction Mostly Yes, the only one of the four No, commits as it goes No, commits as it goes A failed schema step leaves Normally nothing applied Nothing applied A partly built database A partly built database Isolation the server uses READ UNCOMMITTED its default its default its default Transactions used at all yes yes only if every table reports InnoDB at connect time asked for, but a no-op: SQLCEConnection::BeginTransaction returns true without starting one (Roadmap.md) Choose it when You already run SQL Server You want a failed schema step to roll back cleanly You already run it As a new installation's default, up to a few dozen mailboxes; as the target of a migration, only for a test rig MySQL and MariaDB since 6.3.4 MySQL 5.7.9 or MariaDB 10.2.2, or later. Since schema 6102 every table is utf8mb4 under utf8mb4_general_ci, InnoDB, with ROW_FORMAT=DYNAMIC, and a key over a varchar(255) is then 1020 bytes: more than the 767 bytes an InnoDB key part may be in the older COMPACT rows, and within the 3072 bytes these releases, as they ship, take. Why. MySQL's utf8 is three bytes a character, so an emoji in a contact, a folder or a signature was refused with error 1366 under strict mode and made a question mark without it. utf8mb4_general_ci is the twin of utf8_general_ci, so an address or a folder compares as it did, but it does not tell characters outside the Basic Multilingual Plane apart: two address books called Family 👪 and Family 🎉 are one name to its unique index. Creating the database yourself: CREATE DATABASE hmailserver CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; GRANT ALL PRIVILEGES ON hmailserver.* TO 'hmailserver'@'%'; The 6102 step also changes the database's own default character set, which needs the ALTER privilege on the database, not only on its tables. Every table must end up InnoDB: the server issues transactions only if all of them report it at connect time, and silently does not otherwise. A database the server creates itself is made utf8mb4 already. The 6.3.4 upgrade on these two rebuilds every table, and on a server older than 5.7.9 or 10.2.2 it stops at 6041 with error 1071, having changed nothing. Databases on Linux covers that step in full, its time, disk and duplicates (error 1062) included, and Upgrading to 6.3.4 the rest of the upgrade. Creating the database on Windows The wizard asks only "built-in or external". For the built-in engine, DBSetupQuick.exe creates the database at the current schema version, 6104. For an external engine, DBSetup.exe runs after the file copy, asks for the connection, and either creates the database or attaches one that exists; the secure defaults of a new 6.3.4 installation are applied only to one it created. Since 6.3.4 the administrator password reaches both tools in the environment variable HM_ADMIN_PASSWORD, never on a command line. The tools write [Database] in Bin\hMailServer.INI: Key Meaning Type MSSQL, MYSQL, PostgreSQL or MSSQLCE, matched case-insensitively Server, Database, Username, Password The connection. Server is empty for the internal engine PasswordEncryption Written by the server; says how Password is protected Port 0 uses the backend's default Internal 1 only for the embedded engine NumberOfConnections Pool size; default 5 The password in this file may be machine-bound. With ProtectStoredSecretsWithDPAPI=1, the default, the server writes Password through machine-scoped DPAPI (PasswordEncryption=6), and it cannot be decrypted on another machine. If you are also moving hosts, set the password on the new machine through DBSetup.exe rather than copying the encrypted one across. Under NT SERVICE\hMailServer, the account a new 6.3.4 installation runs as, hMailServer.INI is read-only to the service, and the COM methods the two tools call to write [Database] are refused before anything is made. The installer therefore runs its database step while the service is still LocalSystem. To change the database later, move the service to LocalSystem for the change and back (Installing on Windows has the commands), or edit [Database] by hand and restart. Encrypting the connection (since 6.3.4) The test lab measured on 25 September 2026 that the connection to MySQL and MariaDB through MariaDB Connector/C, the client bundled on Windows and the one Ubuntu packages, was never encrypted: every account was reached in plaintext, password exchange, queries and rows alike, and one made with REQUIRE SSL refused the server. Since 6.3.4 two keys under [Database] choose the behaviour: [Database] TlsMode=verify-full TlsCaFile=C:\hMailServer\certs\database-ca.pem TlsMode What the connection does (empty, the default) prefer: TLS whenever the server offers it, and the connection without it when the server offers none, or when the TLS it offers cannot be agreed on (one attempt with TLS and one without, for that failure only). The certificate is not checked prefer As the default, said explicitly disable No TLS. SQL Server's providers still encrypt the login itself require TLS or no connection; the certificate is not checked verify-full TLS or no connection, the certificate checked: its chain to a CA in TlsCaFile (or the system's trust store when that is empty; since 6.3.8 an empty one is refused, HM7535, on MySQL and MariaDB through MariaDB Connector/C to a database server on this machine), and its name or address against Server= TlsCaFile is a PEM file of CA certificates, read by verify-full and by nothing else, so that a CA file left beside require cannot quietly make it stronger or weaker than it says. A TlsCaFile that verify-full would read and that is not there refuses the connection (HM7531) rather than falling back to the system's store. Any other word in TlsMode is refused without an attempt (HM7530); verify-ca is refused by name, and PostgreSQL's own PostgreSQLSslMode=verify-ca remains for PostgreSQL. The keys are read at the service's start. Backend Before 6.3.4 Since 6.3.4, with nothing set MySQL / MariaDB, Windows and Linux Plaintext, always TLS whenever offered, unchecked; plaintext when not PostgreSQL, both platforms libpq's default, prefer Unchanged: libpq's prefer, or a PGSSLMODE in the service's environment, stands. TlsMode and TlsCaFile become sslmode and sslrootcert unless PostgreSQLSslMode and PostgreSQLSslRootCert are set, which win. verify-full with no TlsCaFile is sslrootcert=system on Linux (libpq 16 and later), and libpq's own default file on Windows, %APPDATA%\postgresql\root.crt of the service's account SQL Server, Windows The login encrypted and nothing after it, unless the server forced encryption The whole session encrypted through MSOLEDBSQL, when version 18 or later is installed, and through SQLNCLI for a failover partner; through SQLOLEDB only the login, unless TlsMode is require or verify-full SQL Server, Linux Refused: ADO is Windows (HM6390) Unchanged SQL Server Compact A file on this machine Unchanged On MySQL and MariaDB the old AllowUnencryptedConnection is still read and changes nothing: what it described, TLS preferred and plaintext allowed, is the default now. On SQL Server verify-full checks against the Windows certificate store; TlsCaFile is not read (HM7532), and ConnectionStringOptions naming encryption beside a TlsMode is refused (HM7533). Seeing it. The application log says how the connection is protected, once the service has started and again whenever it changes, for example Database connection: PostgreSQL: NOT encrypted: the server offered no TLS (TlsMode prefer, the default); the diagnostics run on the Diagnostics pages carries the same line under Server details. At the service's start a connection refused for TLS is the connect failure it always was, HM4354, with the database client's own reason and a sentence naming the setting to change. --check-database makes one connection with the TLS settings in the configuration, says what it got, and exits 0 connected, 1 not, 2 not configured. It changes nothing, so it runs beside a running service: hmailserver --config /etc/hmailserver/hMailServer.ini --check-database hMailServer.exe --check-database --config C:\hMailServer\try.ini What the server does not do for you. It cannot switch TLS on at the database server or give it a certificate. Under verify-full a MariaDB 11.4 server's own self-signed certificate is accepted without a CA file when the account's password proves it (MariaDB's zero-configuration TLS, for mysql_native_password, ed25519 and parsec accounts), and not once a CA file is named. A database that must refuse a plaintext connection should say so itself: REQUIRE SSL on the MySQL account, hostssl only in pg_hba.conf, Force Encryption on SQL Server. What is thinner than it could be. There is no editor for these keys in the Control Panel or the Deck. require on the MariaDB client is checked after the login, and an unencrypted connection is closed before a statement crosses it: by then a challenge and a response have crossed in the clear for mysql_native_password, caching_sha2_password and ed25519 accounts, and the password itself for an account that signs in through PAM or the clear-text plugin. verify-full refuses before the login. require protects against someone who can listen and not against someone who can alter the traffic, and prefer connects without TLS to a server that seems to offer none; only verify-full protects against someone on the path. And only a login with VIEW SERVER STATE lets SQL Server say whether its session is encrypted. Moving off the built-in database There is no migration tool. Upgrading.md records that as a gap; MigratingDatabaseBackend.md says it is not an omission, because backup and restore are already backend-agnostic: back up, repoint, restore. It works because the archive's XML carries no identity values, and the message store is addressed by domain name, local part and the file's own guid, never by id. Your mail files never move. Before you start. Write down how many domains, accounts, aliases and distribution lists there are, to verify against afterwards. Take a filesystem-level backup of the whole installation. Backup refuses to run if any message row points outside DataFolder ("All messages are not located in the data folder"). The restore refuses an archive taken by a newer hMailServer, so migrate on one version, then upgrade. Keep a copy of hMailServer.ini; the administrator password lives in it, so it carries over. And any mail delivered between the backup and the cutover is lost to the new database: hold inbound traffic, or accept the gap knowingly. Stop the service (Stop-Service hMailServer). Restart it for the backup itself, which runs through the running server, but stop accepting new mail first if you can. Take the backup on Maintenance → Backup & restore with all three of Back up domains, Back up messages and Back up settings. The archive lands as HMBackup <local time>.7z. All three are required: the restore refuses a combination that would delete something and put nothing back, and says so before it changes anything. Set BackupMessagesDBOnly to 1 before both the backup and the restore. Since 6.3.4 it is a stored setting that applies when it is saved, with no restart: set it in the Control Panel, over REST (PUT /api/v1/settings/ini/BackupMessagesDBOnly with 1) or with hmctl ini set BackupMessagesDBOnly 1. On 6.3.3 it was a [Settings] line in the file, read at start, so restart there. Without it, a normal restore empties the live data directory and copies the staged message store into it; with it that step is skipped and your .eml files are never touched. Remove it afterwards. Stop the service again (Stop-Service hMailServer) and wait for it to stop. Create the new database: empty, with a login that may create tables; on MySQL or MariaDB, utf8mb4. Edit [Database] to point at it, with Internal=0. If the service runs as NT SERVICE\hMailServer, move it to LocalSystem first (hMailServer.exe --service-account localsystem /Register) and back once the migration is verified: under the virtual account the COM methods DBSetupQuick.exe calls are refused before anything is made. Then: & "C:\Program Files\hMailServer\Bin\DBSetupQuick.exe" if ($LASTEXITCODE -ne 0) { throw "Database setup failed with exit code $LASTEXITCODE" } On MySQL and SQL Server Compact a creation that fails halfway leaves a partly built database: drop it and start this step again. Restore. Start the service (Start-Service hMailServer). At its first start against the new database the server adopts the file's [Settings] section into the empty store. Before you restore, check BackupMessagesDBOnly on the new database (hmctl ini get BackupMessagesDBOnly, or the Control Panel). The setting has to be identical for the backup and the restore, and the restore runs against the new database, which has a settings store of its own. If it is not 1 there, set it again, which applies when it is saved. That is the case when the old server could not write its line into the file, which it reported as HM5806 or HM5803, and under NT SERVICE\hMailServer, which does not write the file's copy. A restore without it is a normal one, which empties the data directory. Then: $app = New-Object -ComObject hMailServer.Application $app.Authenticate("Administrator", "<password>") $backup = $app.BackupManager.LoadBackup("D:\hmail-migration\HMBackup 2026-08-13 220511.7z") $backup.RestoreDomains = $true $backup.RestoreMessages = $true $backup.RestoreSettings = $true $backup.StartRestore() The server restarts itself at the end; that is expected. Verify all of these, because a partial restore looks like a working server: the domain, account, alias and list counts, against what you wrote down before you started; the folder list over IMAP as a real account; one whole message body; certificates, ports, IP ranges, routes and rules; one message in and one out; and an empty ERROR_hmailserver_<date>.log. Rolling back is exact until you delete the old database, which was only ever read: stop the service, put the original [Database] section back, start the service. Since 6.3.4 the settings come back with it, and a setting changed since the cutover is named as HM5804 on that start, which is the rollback working, not a fault. Ids change, so a script that recorded hm_accounts.accountid will break; key on the address instead. What it does not cover, and where to read more Moving the data folder to different storage is a separate operation, Relocating an installation to another drive; the path is [Directories] DataFolder. Moving to a new machine is Moving to new hardware, and why Windows to Linux is a rebuild. What the backup archive holds, and what it does not, is in Backup and restore. Sources: the wiki's Before You Install, Migrating the Database Backend and Installing on Linux; MigratingDatabaseBackend.md, DatabaseTls.md and Upgrading.md; and sections 3.5 and 33.3 of the public documentation.