Getting Mirth Connect running locally should take five minutes. Instead, most engineers spend an afternoon fighting Java installers, PostgreSQL configuration, port conflicts, self-signed certificate warnings, and an admin interface that turns out to be read-only in the browser. Then they discover that the open-source version they need is not the latest version.
This guide gives you a copy-paste Docker Compose setup for Mirth Connect 4.5.2 — the last open-source release — backed by PostgreSQL 16, with persistent volumes, health checks, multi-channel MLLP ports, and every environment variable documented. We ran through every step on a fresh machine, captured the exact output you will see, and wrote the troubleshooting section from real errors we hit.
By the end, you will have Mirth Connect running, the API verified, the desktop Administrator connected, and a test HL7v2 message flowing through an MLLP listener. Five minutes to run. Ten more to verify.
Environment tested: macOS (ARM64/Apple Silicon), Docker Desktop 4.37, Mirth Connect 4.5.2 (nextgenhealthcare/connect:4.5.2), PostgreSQL 16 Alpine.
Table of Contents
- Prerequisites
- Why Version 4.5.2 Specifically
- Step 1: The Docker Compose File
- Step 2: Start the Stack
- Step 3: Verify the API
- Step 4: Connect the Mirth Administrator Desktop App
- Step 5: Send a Test HL7v2 Message via MLLP
- Environment Variables Reference
- Adding Custom JARs and Libraries
- Configuring Log Levels
- Troubleshooting
- Frequently Asked Questions
- What Comes Next
Prerequisites
You need three things installed before you start.
Docker Desktop (or Docker Engine + Compose plugin on Linux). Any version from the last two years works. Verify with:
docker --version
# Docker version 27.5.1, build 9f9e405
docker compose version
# Docker Compose version v2.32.4Ports available: 8443, 8082 (or 8080 if nothing else uses it), 5433, 6661, 6662, 6663. If port 8080 is taken — OrbStack, a dev server, another container — we remap it. More on that in a moment.
Mirth Administrator Launcher (optional but recommended). The web dashboard at https://localhost:8443 is read-only — it shows the Dashboard and lets you log in and log out, but you cannot create, edit, or deploy channels from it. Channel management requires the desktop Java application. Download it from:
- Mac: https://localhost:8443 after Mirth starts (the landing page has a download link), or install from the
.dmgon the NextGen Connect releases page - Windows: Same download sources,
.exeinstaller - Linux:
.shinstaller from the releases page
We will cover the Administrator setup in Step 4.
Why Version 4.5.2 Specifically
This matters for budgeting and licensing, so let us be direct.
Mirth Connect was open-source under the MPL 2.0 license through version 4.5.2, released in late 2024. Starting with version 4.6.0, NextGen Healthcare moved Mirth Connect to a commercial license. The commercial pricing ranges from approximately $15,000 to $60,000 per year, depending on volume, support tier, and deployment model.
Version 4.5.2 remains fully functional, runs on Java 17, supports all the core integration capabilities (MLLP/TCP, HTTP, FHIR, database readers/writers, JavaScript transformers), and has an active community. For local development, proof-of-concept work, and many production deployments, 4.5.2 is the right choice.
The Docker image nextgenhealthcare/connect:4.5.2 is the official image published by NextGen Healthcare on Docker Hub. It includes OpenJDK Temurin 17.0.13 and the full Mirth Connect server.
If you are evaluating whether you need the commercial version, the primary additions in 4.6+ are enhanced FHIR support, additional connectors, and vendor support. Everything in this guide and the rest of our Mirth series works on 4.5.2.
Step 1: The Docker Compose File
Create a directory for your Mirth project and add a docker-compose.yml:
mkdir mirth-local && cd mirth-local# docker-compose.yml
services:
mirth-db:
image: postgres:16-alpine
container_name: mirth-db
environment:
POSTGRES_DB: mirthdb
POSTGRES_USER: mirthdb
POSTGRES_PASSWORD: mirthdb
ports:
- "5433:5432"
volumes:
- mirth-db-data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U mirthdb"]
interval: 5s
timeout: 3s
retries: 10
mirth-connect:
image: nextgenhealthcare/connect:4.5.2
container_name: mirth-connect
depends_on:
mirth-db:
condition: service_healthy
environment:
DATABASE: postgres
DATABASE_URL: jdbc:postgresql://mirth-db:5432/mirthdb
DATABASE_USERNAME: mirthdb
DATABASE_PASSWORD: mirthdb
VMOPTIONS: "-Xmx512m"
ports:
- "8443:8443" # Mirth Admin GUI (HTTPS, self-signed cert)
- "8082:8080" # HTTP Listener (remapped from 8080)
- "6661:6661" # MLLP Listener (Channel 1)
- "6662:6662" # MLLP Listener (Channel 2)
- "6663:6663" # MLLP Listener (Channel 3)
volumes:
- mirth-appdata:/opt/connect/appdata
restart: unless-stopped
volumes:
mirth-db-data:
mirth-appdata:What Each Section Does
mirth-db (PostgreSQL 16 Alpine):
- Mirth Connect needs a backing database. The Docker image defaults to an embedded Apache Derby database, which works but is single-connection and unsuitable for anything beyond a quick test. PostgreSQL is the production-grade backend.
- We expose PostgreSQL on port 5433 (not the default 5432) to avoid conflicts with any local PostgreSQL installation.
- The health check ensures Mirth does not attempt to connect before PostgreSQL is ready to accept connections. Without this, Mirth's first boot will fail with a JDBC connection error and enter a restart loop.
- The named volume
mirth-db-datapersists your database across container restarts. Your channels, message history, and configuration survivedocker compose downanddocker compose upcycles.
mirth-connect (Mirth Connect 4.5.2):
depends_onwithcondition: service_healthyis the critical line. It tells Docker Compose to wait until the PostgreSQL health check passes before starting the Mirth container. This replaces the fragile "sleep and hope" pattern.DATABASE: postgrestells Mirth to use PostgreSQL instead of the embedded Derby. The otherDATABASE_*variables provide the JDBC connection string and credentials.VMOPTIONS: "-Xmx512m"sets the JVM maximum heap size. The default is 256MB, which is fine for a single channel but will causeOutOfMemoryErrorexceptions when you start running multiple channels with large message volumes. 512MB is a safe starting point for local development. Production deployments typically use 1-2GB.- Port 8082:8080 maps the container's internal HTTP listener port (8080) to 8082 on your host. We use 8082 because port 8080 is commonly occupied by OrbStack, local app servers, or other tools. If your port 8080 is free, you can change this to
8080:8080. - Ports 6661-6663 are pre-allocated for MLLP (Minimal Lower Layer Protocol) listeners. MLLP is the standard transport for HL7v2 messages. Each channel that receives HL7v2 messages needs its own MLLP port. Three ports give you room for three concurrent channels.
- The
mirth-appdatavolume persists Mirth's application data: server configuration, keystores, custom libraries, and extension data.
Step 2: Start the Stack
docker compose up -dExpected output:
[+] Running 3/3
✔ Network mirth-local_default Created 0.0s
✔ Container mirth-db Healthy 5.6s
✔ Container mirth-connect Started 6.1sNow wait. This is the part the official docs do not emphasize enough: Mirth Connect takes approximately 45 seconds on first boot. It is not hung. It is initializing the database schema — creating tables, indexes, and default configuration in your PostgreSQL instance. Subsequent boots are faster (10-15 seconds) because the schema already exists.
Watch the logs to know when it is ready:
docker compose logs -f mirth-connectYou are looking for this line:
mirth-connect | Web server started: https://0.0.0.0:8443Once you see that, Mirth is ready. Press Ctrl+C to exit the log stream.
What the First Boot Actually Does
During the first boot, Mirth Connect:
- Detects that the PostgreSQL database has no Mirth schema
- Creates approximately 40 tables (
d_channels,d_configuration,d_code_template,d_message,d_connector_message, etc.) - Inserts default configuration values (server settings, default admin user, encryption keys)
- Generates a self-signed TLS certificate for the HTTPS admin interface
- Starts the internal web server on port 8443
- Starts listening on any configured channel ports (none yet, since no channels are deployed)
If you are curious about the database schema, you can inspect it directly:
docker exec -it mirth-db psql -U mirthdb -d mirthdb -c "\dt"This shows all tables Mirth created. You will see around 40 tables starting with d_ (for "data") and person tables for user management.
Step 3: Verify the API
Before connecting any GUI tools, verify that Mirth is responding correctly via the REST API. This also confirms that authentication, HTTPS, and the API layer are all working.
Check the Server Version
curl -sk \
-H "X-Requested-With: OpenAPI" \
-H "Accept: text/plain" \
-u admin:admin \
"https://localhost:8443/api/server/version"Expected output:
4.5.2Three things to note about this command:
-kflag: Required because Mirth generates a self-signed TLS certificate on first boot. Without-k, curl will refuse the connection withSSL certificate problem: self-signed certificate. This is expected in local development. In production, you would replace the certificate.-H "X-Requested-With: OpenAPI": This header is mandatory on every Mirth REST API call. Without it, Mirth returns403 Forbiddenwith no error message. This is a CSRF protection mechanism — Mirth checks that the header exists, but the value can be anything (OpenAPI,curl,XMLHttpRequest). If you forget this header, you will spend twenty minutes debugging a perfectly good API call.-u admin:admin: Default credentials. The default username isadminand the default password isadmin. Change this before exposing Mirth to any network beyond localhost.
Check Server Status
curl -sk \
-H "X-Requested-With: OpenAPI" \
-H "Accept: application/json" \
-u admin:admin \
"https://localhost:8443/api/server/status"Expected output:
{"string":"RUNNING"}List Channels (Will Be Empty)
curl -sk \
-H "X-Requested-With: OpenAPI" \
-H "Accept: application/json" \
-u admin:admin \
"https://localhost:8443/api/channels"Expected output:
{"list":{"channel":[]}}An empty channel list confirms the server is ready and waiting for you to create channels. We will do that via the Administrator in the next step.
Visit the Web Dashboard
Open https://localhost:8443 in your browser. You will see a certificate warning because of the self-signed cert. In Chrome, click "Advanced" then "Proceed to localhost (unsafe)." In Firefox, click "Advanced" then "Accept the Risk and Continue."
The web interface presents a login page. Log in with admin / admin.
Important limitation: The web dashboard is read-only. You can view the Dashboard (channel status, message counts, server statistics) and that is it. You cannot create channels, edit transformers, deploy or undeploy channels, or manage server settings from the browser. All channel management requires the Mirth Administrator desktop application.
This catches many developers by surprise. Mirth Connect's web interface is a monitoring dashboard, not a management console. The full management experience requires the desktop Java client.
Step 4: Connect the Mirth Administrator Desktop App
The Mirth Administrator is a Java-based desktop application that connects to your Mirth server over HTTPS (port 8443). This is where you create channels, write transformers, configure connectors, deploy channels, and view message logs.
Installing the Administrator
Option A: Download from Your Running Instance
Navigate to https://localhost:8443 in your browser. The landing page (before you log in) includes links to download the Mirth Administrator Launcher for your platform.
Option B: Download from GitHub Releases
Go to https://github.com/nextgenhealthcare/connect/releases/tag/4.5.2 and download the Administrator Launcher for your OS:
mirthconnect-administrator-launcher-4.5.2-mac.dmgfor macOSmirthconnect-administrator-launcher-4.5.2-windows.exefor Windowsmirthconnect-administrator-launcher-4.5.2-unix.shfor Linux
Option C: Already Installed
On macOS, check /Applications/ for "Mirth Connect Administrator Launcher." If you have installed Mirth locally before, it may already be there.
Connecting to Your Docker Instance
- Launch the Mirth Administrator Launcher
- In the server address field, enter:
https://localhost:8443 - Username:
admin - Password:
admin - Click "Login"
You will see a certificate warning because of the self-signed cert. Accept it. The Administrator will connect to your Docker-hosted Mirth server and present the full management interface: Channels, Dashboard, Users, Settings, Alerts, and Events panels.
First Steps in the Administrator
Once connected, you will see an empty Channels panel. From here you can:
- Create a new channel: Right-click in the Channels panel or use the "New Channel" button
- Set the channel name and description
- Configure the Source connector: TCP Listener (MLLP), HTTP Listener, Database Reader, File Reader, etc.
- Add filters and transformers: JavaScript, mapping, or rule-based
- Configure Destination connectors: Channel Writer, HTTP Sender, Database Writer, TCP Sender, File Writer
- Deploy the channel: Right-click the channel and select "Deploy" or use the toolbar
For a complete guide to building your first channel with business logic and FHIR transformation, see our HL7v2-to-FHIR pipeline guide.
Step 5: Send a Test HL7v2 Message via MLLP
Before you build any channels, let us verify that you can send an HL7v2 message to Mirth over MLLP. This tests the entire pipeline from your machine into the Docker container.
First, you need a channel listening on one of the MLLP ports. If you have not created a channel yet, create a minimal one in the Mirth Administrator:
- Create a new channel named "Test MLLP Receiver"
- Set the Source connector to TCP Listener
- Set the port to 6661
- Set the transmission mode to MLLP
- Leave the destination as the default Channel Writer (which just logs the message)
- Save and deploy the channel
Now send a test ADT^A01 message. MLLP wraps HL7v2 messages in a specific framing protocol: a start byte (0x0B), the message content, an end byte (0x1C), and a carriage return (0x0D). Here is a Python script that handles the framing correctly:
#!/usr/bin/env python3
"""
send_hl7_test.py - Send a test HL7v2 ADT^A01 message via MLLP.
Usage: python3 send_hl7_test.py [host] [port]
"""
import socket
import sys
from datetime import datetime
# MLLP framing bytes
MLLP_START = b'\x0b' # Vertical Tab (VT)
MLLP_END = b'\x1c' # File Separator (FS)
MLLP_CR = b'\x0d' # Carriage Return (CR)
def build_adt_a01():
"""Build a minimal but valid HL7v2 ADT^A01 message."""
timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
segments = [
f'MSH|^~\\&|TESTAPP|TESTFAC|MIRTH|MIRTHFAC|{timestamp}||ADT^A01^ADT_A01|MSG{timestamp}|P|2.5.1|||AL|NE',
f'EVN|A01|{timestamp}',
'PID|1||PAT001^^^TESTFAC^MR||DOE^JANE^M||19850215|F|||123 MAIN ST^^SPRINGFIELD^IL^62701||2175551234|||S|||999-88-7777',
f'PV1|1|I|ICU^101^A^TESTFAC||||1234^SMITH^JOHN^DR|||MED||||7|||1234^SMITH^JOHN^DR|IP|V001^^^TESTFAC|||||||||||||||||||||||||{timestamp}',
'IN1|1|BCBS001^BLUE CROSS|INS001|BLUE CROSS BLUE SHIELD|||||||||||DOE^JANE|SELF|19850215|123 MAIN ST^^SPRINGFIELD^IL^62701',
'DG1|1||A41.9^Sepsis unspecified organism^I10||20240115|A',
]
return '\r'.join(segments)
def send_mllp(host, port, message):
"""Send an HL7v2 message using MLLP framing and return the ACK."""
mllp_message = MLLP_START + message.encode('ascii') + MLLP_END + MLLP_CR
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.settimeout(10)
print(f'Connecting to {host}:{port}...')
sock.connect((host, port))
print(f'Connected. Sending {len(message)} bytes...')
sock.sendall(mllp_message)
print('Message sent. Waiting for ACK...')
# Read the response (ACK)
response = b''
while True:
chunk = sock.recv(4096)
if not chunk:
break
response += chunk
if MLLP_END in response:
break
# Strip MLLP framing from response
ack = response.replace(MLLP_START, b'').replace(MLLP_END, b'').replace(MLLP_CR, b'')
return ack.decode('ascii', errors='replace')
if __name__ == '__main__':
host = sys.argv[1] if len(sys.argv) > 1 else 'localhost'
port = int(sys.argv[2]) if len(sys.argv) > 2 else 6661
message = build_adt_a01()
print(f'\n--- HL7v2 ADT^A01 Message ---')
for seg in message.split('\r'):
print(seg)
print(f'--- End Message ---\n')
ack = send_mllp(host, port, message)
print(f'\n--- ACK Response ---')
for seg in ack.split('\r'):
print(seg)
print(f'--- End ACK ---\n')
if 'AA' in ack:
print('Result: MESSAGE ACCEPTED (AA)')
elif 'AE' in ack:
print('Result: APPLICATION ERROR (AE)')
elif 'AR' in ack:
print('Result: APPLICATION REJECT (AR)')
else:
print('Result: UNEXPECTED RESPONSE')Save this as send_hl7_test.py and run it:
python3 send_hl7_test.py localhost 6661Expected output:
--- HL7v2 ADT^A01 Message ---
MSH|^~\&|TESTAPP|TESTFAC|MIRTH|MIRTHFAC|20260527120000||ADT^A01^ADT_A01|MSG20260527120000|P|2.5.1|||AL|NE
EVN|A01|20260527120000
PID|1||PAT001^^^TESTFAC^MR||DOE^JANE^M||19850215|F|||123 MAIN ST^^SPRINGFIELD^IL^62701||2175551234|||S|||999-88-7777
PV1|1|I|ICU^101^A^TESTFAC||||1234^SMITH^JOHN^DR|||MED||||7|||1234^SMITH^JOHN^DR|IP|V001^^^TESTFAC|||||||||||||||||||||||||20260527120000
IN1|1|BCBS001^BLUE CROSS|INS001|BLUE CROSS BLUE SHIELD|||||||||||DOE^JANE|SELF|19850215|123 MAIN ST^^SPRINGFIELD^IL^62701
DG1|1||A41.9^Sepsis unspecified organism^I10||20240115|A
--- End Message ---
Connecting to localhost:6661...
Connected. Sending 687 bytes...
Message sent. Waiting for ACK...
--- ACK Response ---
MSH|^~\&|MIRTH|MIRTHFAC|TESTAPP|TESTFAC|20260527120001||ACK^A01|ACK20260527120001|P|2.5.1
MSA|AA|MSG20260527120000
--- End ACK ---
Result: MESSAGE ACCEPTED (AA)If you see MESSAGE ACCEPTED (AA), the full path is working: your machine, through Docker port mapping, into the Mirth Connect container, processed by the channel, and an ACK returned.
Check the Mirth Administrator Dashboard to see the message appear in the channel's received message count. You can click on the channel and view the raw message content in the Messages tab.
Environment Variables Reference
The Mirth Connect Docker image accepts these environment variables. Most have sensible defaults, but knowing what they do saves you time when you need to customize.
| Variable | Default | Description |
|---|---|---|
DATABASE | derby | Database type. Set to postgres for PostgreSQL, mysql for MySQL, sqlserver for SQL Server, oracle for Oracle. |
DATABASE_URL | (Derby path) | JDBC connection URL. For PostgreSQL: jdbc:postgresql://host:port/dbname |
DATABASE_USERNAME | (none) | Database username. |
DATABASE_PASSWORD | (none) | Database password. |
DATABASE_MAX_CONNECTIONS | 20 | Maximum database connection pool size. |
VMOPTIONS | "-Xmx256m" | JVM options passed to the Mirth server process. Common additions: -Xmx512m (heap size), -Xms256m (initial heap). |
KEYSTORE_STOREPASS | 81uWxplDtB | Password for the Java keystore (TLS certificate store). Change this in production. |
KEYSTORE_KEYPASS | 81uWxplDtB | Password for the private key within the keystore. Change this in production. |
JVM Memory Tuning
The VMOPTIONS variable is where you control JVM memory. For local development with one to three channels:
VMOPTIONS: "-Xmx512m"For running 10+ channels or handling high message volumes locally:
VMOPTIONS: "-Xmx1g -Xms512m"For production deployments:
VMOPTIONS: "-Xmx2g -Xms1g -XX:+UseG1GC"If you see java.lang.OutOfMemoryError: Java heap space in the logs, increase -Xmx.
Adding Custom JARs and Libraries
Mirth Connect supports loading additional Java libraries at startup via the custom-lib directory. This is essential for features like making HTTP API calls from JavaScript transformers (which requires Apache HttpClient JARs, as we documented in our HTTP API calls guide).
Setup
- Create a
custom-libdirectory and add your JARs:
mkdir custom-lib
# Example: Add Apache HttpClient for transformer HTTP calls
curl -L -o custom-lib/httpclient-4.5.13.jar \
https://repo1.maven.org/maven2/org/apache/httpcomponents/httpclient/4.5.13/httpclient-4.5.13.jar
curl -L -o custom-lib/httpcore-4.4.13.jar \
https://repo1.maven.org/maven2/org/apache/httpcomponents/httpcore/4.4.13/httpcore-4.4.13.jar- Mount the directory into the container by adding a volume to your
docker-compose.yml:
mirth-connect:
# ... existing config ...
volumes:
- mirth-appdata:/opt/connect/appdata
- ./custom-lib:/opt/connect/custom-lib- Enable custom library loading in Mirth. After Mirth starts, go to the Administrator: Settings > Server > Configuration Map and set:
server.includecustomlib = trueAlternatively, you can set this in the mirth.properties file inside the appdata volume. But the Configuration Map approach is simpler for Docker deployments.
- Restart Mirth to pick up the new JARs:
docker compose restart mirth-connectThe JARs in custom-lib are now available to all transformer JavaScript code via Java's Packages global. For example:
var HttpClients = Packages.org.apache.http.impl.client.HttpClients;
var HttpGet = Packages.org.apache.http.client.methods.HttpGet;
var client = HttpClients.createDefault();Configuring Log Levels
By default, Mirth Connect logs at the ERROR level. This means you see nothing in the logs unless something fails. During development, this is unhelpful — you want to see what Mirth is doing, which channels are processing messages, and what the transformers are producing.
Changing the Log Level
The logging configuration lives in /opt/connect/conf/log4j2.properties inside the container. To change it:
Option 1: Exec into the container and edit directly
docker exec -it mirth-connect bash
vi /opt/connect/conf/log4j2.propertiesFind the line:
rootLogger.level = ERRORChange it to:
rootLogger.level = INFOThen restart Mirth:
docker compose restart mirth-connectOption 2: Mount a custom log4j2.properties file
Create a local log4j2.properties file with your desired level and mount it:
mirth-connect:
# ... existing config ...
volumes:
- mirth-appdata:/opt/connect/appdata
- ./log4j2.properties:/opt/connect/conf/log4j2.propertiesRecommended Levels for Development
| Level | Use Case |
|---|---|
ERROR | Production: only log failures |
WARN | Production: log failures and suspicious conditions |
INFO | Development: log channel lifecycle events, deployments, connections |
DEBUG | Troubleshooting: log message processing details, transformer execution |
TRACE | Deep debugging: log everything including raw message bytes (very verbose) |
For most local development work, INFO is the sweet spot. DEBUG generates significant log volume and should only be used when investigating a specific issue.
Troubleshooting
Every error in this section is one we hit during our setup. The error messages are exact.
"Connection refused" when accessing https://localhost:8443
Symptom: Browser or curl shows Connection refused immediately.
Cause 1: Mirth is still booting. The first boot takes ~45 seconds. Check the logs:
docker compose logs mirth-connect | tail -20If you see database initialization messages but no "Web server started" line, wait.
Cause 2: The container crashed. Check if the container is running:
docker compose psIf the status shows "Exited" or "Restarting," check the logs for the root cause:
docker compose logs mirth-connectCause 3: PostgreSQL failed to start first. If the health check is not working, Mirth may have tried to connect to PostgreSQL before it was ready and crashed. This manifests as:
SEVERE: Could not retrieve database schema.
org.postgresql.util.PSQLException: Connection to mirth-db:5432 refused.Fix: Ensure your depends_on block uses condition: service_healthy, not just depends_on: [mirth-db]. The bare syntax only waits for the container to start, not for PostgreSQL to be ready.
403 Forbidden on API calls
Symptom:
curl -sk -u admin:admin "https://localhost:8443/api/server/version"
# Returns: 403 Forbidden (empty body)Cause: Missing X-Requested-With header. This is the single most common Mirth API mistake. Every API call requires this header:
curl -sk -u admin:admin \
-H "X-Requested-With: OpenAPI" \
"https://localhost:8443/api/server/version"The header value does not matter. OpenAPI, curl, XMLHttpRequest, anything — Mirth only checks that the header exists. This is CSRF protection.
SSL certificate problem: self-signed certificate
Symptom:
curl -s -u admin:admin -H "X-Requested-With: OpenAPI" "https://localhost:8443/api/server/version"
# curl: (60) SSL certificate problem: self-signed certificate in certificate chainCause: Mirth generates a self-signed certificate on first boot. Use the -k flag with curl to skip certificate verification:
curl -sk ...In Python requests, use verify=False. In Node.js, set rejectUnauthorized: false. In production, replace the self-signed certificate with a proper one.
Port 8080 already in use
Symptom:
Error response from daemon: Ports are not available: exposing port TCP 0.0.0.0:8080 -> 0.0.0.0:0: listen tcp 0.0.0.0:8080: bind: address already in useCause: Another process (OrbStack, a dev server, Tomcat, Jenkins) is using port 8080. Either stop the other process or remap the port in docker-compose.yml:
ports:
- "8082:8080" # Map container port 8080 to host port 8082Find what is using 8080:
lsof -i :8080OutOfMemoryError
Symptom:
java.lang.OutOfMemoryError: Java heap spaceCause: The JVM heap size is too small for your workload. Increase it in docker-compose.yml:
environment:
VMOPTIONS: "-Xmx1g"Then restart:
docker compose restart mirth-connectChannel deploys but does not receive messages
Symptom: Channel shows as "Started" in the Dashboard, but sending MLLP messages to the port returns Connection refused.
Cause 1: Port not mapped in docker-compose.yml. The channel is listening inside the container, but the port is not exposed to your host. Add the port to the ports section:
ports:
- "6661:6661"Cause 2: Channel is listening on a different port than you expect. Open the channel in the Administrator and check the Source connector port number. It must match one of the ports you have mapped.
Cause 3: Channel needs redeployment. After changing the port in the channel configuration, you must redeploy the channel. Right-click the channel and select "Redeploy."
Mirth Connect Administrator cannot connect
Symptom: The Administrator Launcher shows "Could not connect to server" or times out.
Cause 1: Wrong URL. The URL must be https://localhost:8443 (not http://). Mirth's admin interface is HTTPS-only.
Cause 2: Firewall or VPN. If you are on a corporate network, a VPN or firewall may be blocking localhost connections on non-standard ports. Try temporarily disconnecting the VPN.
Cause 3: Certificate rejection. Some Java versions are stricter about self-signed certificates. The Administrator Launcher should prompt you to accept the certificate. If it does not, check that your Java version is compatible (Java 8+ for the launcher).
Need expert help with healthcare interoperability and integration engines? Explore our Healthcare Interoperability Solutions to see how we connect systems seamlessly. We also offer specialized Healthcare Software Product Development services for building production-grade integration infrastructure. Talk to our team to get started.
What Comes Next
This guide gets you from zero to a running Mirth Connect instance with verified API access and message flow. The rest of this series builds on this foundation:
- How to Make HTTP API Calls from Mirth Connect Transformers on Java 17 — The working solution for outbound HTTP calls from transformer JavaScript, after java.net.URL breaks on Java 17.
- Building a Production-Grade HL7v2 to FHIR R4 Pipeline — A complete channel with 8 mapping tables, clinical business rules, dual ICD-10/SNOMED CT coding, and live terminology validation.
- HL7v2 to openEHR Composition Mapping — Transforming ADT messages to openEHR FLAT format for clinical data repositories, with all 42 fields mapped.
- Mirth Connect REST API: The Undocumented Gotchas — Seven production-breaking issues with channel management via the API, each with the exact error message and the fix.



