Overview
Many Mango by Radix IoT installations start on the default H2 database, and nothing in Mango disqualifies H2 from production. Move the SQL database to MySQL or PostgreSQL when you need what H2 cannot do: access to the database from outside Mango while it runs, replication, or backup and restore that do not depend on Mango. How to Choose and Configure Your Mango Database (MySQL, PostgreSQL, MariaDB) covers that decision.
Mango has a built-in database conversion for exactly this, and it is the method to use. You configure the empty target under the db.* properties, point convert.db.* at your existing H2 database, and Mango copies the tables across on startup — Core schema tables plus the tables belonging to every loaded module. This preserves the actual database contents, including relational IDs, event and audit history, and module data.
Danger
Changing db.* to a new database and restarting is not a migration. Without convert.db.type set, Mango sees a database that does not exist yet, creates an empty schema, and starts as a brand-new installation. Your users, data sources, and data points will appear to be gone. They are still in the H2 files, but you will be looking at an empty Mango on what may be a production system.
Supported Target Databases
Mango's DatabaseType lists five names — DERBY, H2, MSSQL, MYSQL and POSTGRES — but only MySQL and PostgreSQL are conversion targets. DERBY is deprecated, with no driver and no proxy left in the product. MSSQL has a proxy but no bundled driver, and the conversion itself rejects it: after copying each table Mango resets that table's autoincrement sequence, and that step is implemented for H2, PostgreSQL and MySQL only, so any other target fails on the first table with an identity column.
There is no separate MariaDB database type. MariaDB is wire-compatible with MySQL and may work through the MySQL type and driver, but that is a compatibility assumption rather than a distinct supported target — check the supported-versions documentation for your release, and test the full conversion on a disposable instance before committing a production system to it.
MySQL must be at least 5.7.8; Mango checks for JSON column support at startup and refuses to start on older versions.
Note
Do not copy a JDBC driver into lib. Mango 5.7.4 already ships the H2, MySQL and PostgreSQL connectors, and adding a second copy risks a classpath conflict that is harder to diagnose than the problem it was meant to solve. No SQL Server driver ships at all, which is the other reason MSSQL is not a route off H2.
Prerequisites
- Back up everything — take a full Mango backup (SQL database + NoSQL + mango.properties + file store). This is your only route back
- Do not combine this with an upgrade — upgrade Mango first, confirm the system is healthy on H2, then convert as a separate exercise. Running both at once is explicitly not supported
- Plan downtime — conversion happens during a Mango startup, and it copies row by row. How long it takes tracks the number of rows in your SQL tables, which in practice means event and audit history; time-series point values are not copied and do not affect it
- Create the target database — the database and its user must already exist and be reachable. Mango creates the tables; it does not create the database
- The target must be empty — conversion only runs when Mango finds no existing schema in the target. Pointing it at a database that already has Mango tables skips conversion entirely
- Rehearse on a staging copy first — take a copy of the H2 files onto a disposable instance and run the whole procedure there. Copy the whole
databasesdirectory: Mango appends H2's own build number to the base name, so the file on disk ismah2.<build>.mv.db, notmah2.mv.db
Migration Method: Built-In Database Conversion
Step 1: Stop Mango
Shut down the Mango service cleanly and confirm the process has exited before touching the H2 files.
Step 2: Create the Target Database
Create an empty database and a user with full rights on it (see How to Choose and Configure Your Mango Database (MySQL, PostgreSQL, MariaDB)). Confirm you can connect to it from the Mango host before going further.
Step 3: Configure Both Ends in mango.properties
The db.* block describes where you are going. The convert.db.* block describes where you are coming from.
# Target: the new, empty production database
db.type=postgres
db.url=jdbc:postgresql://localhost/mango
db.username=mango
db.password=<target password>
# Source: the existing H2 database you are converting from
convert.db.type=h2
convert.db.url=jdbc:h2:databases/mah2
convert.db.username=
convert.db.password=
For a MySQL target, use db.type=mysql with a jdbc:mysql://... URL instead.
Warning
convert.db.username and convert.db.password ship as ${db.username} and ${db.password}, so leaving them unset makes them inherit the production credentials you just set for the target, and H2 refuses the connection. A default H2 database has an empty username and password. Set both explicitly, even when the correct value is blank.
Copy the H2 URL from the db.url value the installation was using before your edit, so the source path is exactly right. The path is relative to the data directory unless it is absolute.
Step 4: Start Mango and Watch the Conversion
Start Mango and follow ma.log. Conversion runs during startup, before normal operation, and logs its progress at warning level: it announces the conversion from source type to target type, names each table as it is copied, reports the record count for each, and finally logs that the conversion has completed.
Do not interrupt this. Table copying happens inside transactions, and tables with foreign key dependencies are automatically retried after the tables they reference have been copied, so out-of-order warnings during the run are expected.
Step 5: Remove the Conversion Setting
Once the conversion has completed and you have verified the result, clear convert.db.type back to blank. Leaving it set is harmless while the target has a schema — conversion is gated on the target being new — but clearing it removes any chance of a future empty-target situation re-running it unexpectedly.
Step 6: Verify
- Log in and confirm your existing users are present — including their passwords
- Check that all data sources appear, are enabled, and are polling
- Verify data points are collecting new values
- Confirm historical data is queryable
- Check dashboards, watch lists, and reports
- Verify event detectors and handlers are active, and that event history is present
Historical Data and the NoSQL Store
This conversion moves the SQL database only. Time-series point values live in a separate point value store, commonly the NoSQL database under the data directory, and are untouched by the conversion.
Leave db.nosql.location and db.nosql.pointValueStoreName pointing at the same directory they already used and your history carries over unchanged. This is also why history is not something you can lose to a botched SQL conversion — but it is equally why a successful SQL conversion tells you nothing about the health of your history. Verify both.
What the Conversion Covers
| Converted | Not part of the SQL conversion |
|---|---|
| Core schema tables — users, roles, permissions, data sources, data points, event detectors and handlers, system settings | Time-series point values (separate store, left in place) |
| Schema tables belonging to every loaded module | The H2 files themselves, left untouched on disk — your rollback path |
| Event and audit history held in SQL | Generated report output, which is written to a file store on disk and stays there |
| Relational IDs and autoincrement sequences, which are reset to stay consistent after the copy | Files in the file store (left in place on disk) |
Note
Only tables declared by Core and by the modules loaded at conversion time are copied. If a module is installed on the source but not present when you convert, its tables are not carried over. Have the same module set installed before you start.
Alternative: JSON Export/Import
Mango's configuration export/import can move configuration between installations, and it has its uses — moving a subset of configuration between environments, or as a fallback when direct conversion is not viable. It is not equivalent to a database conversion and should not be presented as the same operation.
What a JSON export/import does not carry across:
- Relational identifiers — objects are recreated in the target and receive new internal IDs
- Event history and audit history
- Active event state
- Any module data that is not represented in the export format
User password hashes can be exported and imported, but the importer skips the user currently performing the import, so do not assume every account arrives ready to log in. If you use this path, test the resulting user accounts explicitly rather than promising an identical restoration.
When the goal is converting the SQL database with its contents intact, use the built-in conversion.
Verification
Work the full post-migration checklist before you consider the conversion done:
- ☐
ma.logshows the conversion completing, and the per-table record counts match the row counts in the H2 source — not just that it finished - ☐ Existing users are present and can log in with their previous credentials
- ☐ All data sources enabled and polling
- ☐ Data points receiving new values
- ☐ Historical data accessible (point value store unchanged)
- ☐ Event and audit history present
- ☐ Dashboards and watch lists display correctly
- ☐ Event detectors are active
- ☐ Email handlers can send (test SMTP)
- ☐
convert.db.typecleared back to blank - ☐ Backups configured for the new database, and the old H2 files retained until you are confident
- ☐ Monitor for errors in ma.log for 24 hours
Troubleshooting
| Issue | Cause | Fix |
|---|---|---|
| Mango starts empty, with only the default admin | convert.db.type was blank, so Mango created a fresh schema instead of converting | Stop Mango, drop the empty target schema so the target is new again, set the convert.db.* properties, and start again. The H2 data is untouched |
| The log shows the conversion running and completing, but Mango still has only the default admin and every table reports a handful of records | convert.db.url pointed at an H2 database that is not there. Mango does not require the file to exist — H2 creates it, Mango builds a fresh schema and default admin inside it, and the conversion then faithfully copies that empty installation into your target | Stop Mango, drop the target schema, and set convert.db.url to the exact value db.url held before your edit. This is why you read the record counts rather than the completion line |
| No conversion appears in the log and the target already has data | Conversion only runs when the target has no existing schema | Convert into a genuinely empty database |
| Conversion fails connecting to the source | convert.db.username and convert.db.password inherited the target credentials | Set them explicitly for H2, usually to blank, and check the convert.db.url path |
| Startup fails naming a MySQL version | MySQL older than 5.7.8 lacks the JSON column support Mango requires | Upgrade MySQL, or target PostgreSQL instead |
| Schema version errors during startup | An upgrade and a conversion were attempted together | Restore the backup, upgrade on H2 first, confirm the system is healthy, then convert |
| Some module data is missing after conversion | That module was not loaded when the conversion ran, so its tables were not copied | Restore, install the same module set as the source, and convert again into a fresh target |
| Historical data missing | Point value store location changed along with the SQL settings | Verify db.nosql.location and db.nosql.pointValueStoreName point at the existing store |
| Driver or classpath errors | A JDBC driver was added to lib alongside the bundled connector | Remove the added driver and rely on the bundled one |
Summary
Convert from H2 using Mango's built-in database conversion: create an empty MySQL or PostgreSQL database, point db.* at it, point convert.db.* at the existing H2 database, and start Mango. Mango copies the Core and module schema tables across, preserving contents rather than recreating configuration. Changing db.* alone does not migrate anything — it starts a new, empty installation. Do not combine the conversion with a Mango upgrade, do not add JDBC drivers to lib, and remember the time-series point value store is separate and stays where it is. Always back up first and rehearse the whole procedure on a disposable copy.