MLLP Protocol
The Minimal Lower-Layer Protocol — the framing convention that lets HL7v2 messages travel across a TCP connection.
HL7v2 was designed as a content standard, not a transport. The standard says what a message looks like — its segments, fields, and delimiters — but it does not, by itself, say how those bytes travel from one machine to another. MLLP is the convention that fills the gap. It is small, old, and almost universal: nearly every HL7v2 deployment in production speaks it.
MLLP stands for Minimal Lower-Layer Protocol. The "minimal" is honest. The protocol is a thin framing layer over TCP — three special bytes around each message — and almost nothing else. Its purpose is not to add features but to give a stream of bytes the message boundaries that TCP does not provide. It is the simplest way to send HL7v2 messages over a network without ambiguity.
Good to know
Some modern deployments use HL7v2 over HTTP or HL7v2 over TLS, which do not require MLLP framing. But MLLP remains the dominant transport for HL7v2 in production, especially in hospital integration scenarios.
Transmission Control Protocol
Transmission Control Protocol (TCP) is a fundamental protocol of the internet. It provides a reliable, ordered, and error-checked delivery of a stream of bytes between applications running on hosts communicating over an IP network. TCP is a transport protocol, not a message protocol — it delivers a stream of bytes.
TCP does not preserve message boundaries. A sender that writes one HL7v2 message and a receiver that reads from the connection have no built-in agreement about where the message ends — the receiver only sees bytes arriving, possibly in chunks of any size, possibly with the next message's bytes already attached.
Two messages sent back to back on the same connection appear at the receiver as a single string of bytes containing two messages. Without a framing convention, the receiver has to guess where one ends and the next begins — and the guess will eventually be wrong.
MLLP
MLLP is a convention for framing HL7v2 messages on a TCP connection. It defines a simple way to mark the start and end of each message, so the receiver can read bytes until it sees the end marker, treat everything between the markers as one message, and then start again on the next. In other words, each HL7v2 message is wrapped in a marker byte at the start and a two-byte sequence at the end. The receiver reads bytes until it sees the end sequence, treats everything between the markers as one message, and starts again on the next.
The frame
A single MLLP frame has three parts.
End FS 0x1C CR 0x0D Payload HL7v2 message bytes Start VT 0x0B
| Position | Bytes | Name |
|---|---|---|
| Start | 0x0B | Vertical tab (<VT>) |
| Payload | variable | The HL7v2 message bytes |
| End | 0x1C 0x0D | File separator (<FS>) followed by carriage return (<CR>) |
0x0B and 0x1C are ASCII C0 control characters — VT (vertical tab) and FS (file separator) — originally used in the paper-tape and teleprinter era. Neither appears in HL7v2 payloads, which is what makes them safe as frame markers. The trailing 0x0D is a plain carriage return (CR): the same byte HL7v2 uses to separate segments inside the message.
Within the payload, the HL7v2 message looks the same as it would on disk or in a file: segments separated by <CR>, fields separated by |, and so on. MLLP does not change the message; it only delimits it.
Connection lifecycle
MLLP runs over a TCP connection that is typically opened once and reused for many messages. By convention, the receiver listens on port 2575, although this is configuration, not standard.
Once the connection is open, the conversation is a sequence of frames. The sender writes a frame; the receiver reads it, processes the message, and writes back an acknowledgment — itself an HL7v2 message, framed the same way. Then the next frame, and the next. The connection stays open until either side closes it.
This long-lived shape is a deliberate choice. Opening a TCP connection has a cost — the three-way handshake, any TLS negotiation if the connection is encrypted — and a hospital integration partner that sends a thousand messages an hour does not want to pay that cost a thousand times. The connection is opened once and held open for the work day, with frames arriving on it as events happen in the source system.
A consequence is that MLLP receivers have to keep state per connection. They track partial frames (a frame that arrived in two TCP reads), apply per-connection timeouts (a connection that has gone quiet for an hour), and decide what to do when a connection closes mid-frame. None of this is in the protocol; all of it is the receiver's responsibility.
Glion MLLP client does not support long-lived connections
The current implementation of the Glion MLLP client does not support streaming multiple messages on the same connection. It opens a new connection for each message, which is simpler but less efficient. Support for long-lived connections and multiple frames per connection is on the roadmap.
Acknowledgment, not response
The ack frame deserves a closer look because it is easy to mistake for an HTTP-style response.
The acknowledgment to an HL7v2 message is itself an HL7v2 message — usually an ACK message type, with an MSA segment carrying the result code (AA, AE, or AR). The receiver writes this ack as a new MLLP frame on the same TCP connection, with its own start byte and end sequence. There is no protocol-level pairing of request and response; MLLP does not know that the second frame is a reply to the first. The receiver knows because the application logic builds the ack from the original message's control id (MSH-10) and writes it back.
This is unusual to readers from a web background. In HTTP, the response is structurally bound to the request — same connection, same exchange, framed by the protocol itself. In MLLP, the ack is just another framed message that happens to arrive next, and the application is responsible for matching it to the original by control id. A sender that has multiple outstanding messages on the same connection must therefore match acks back to messages in code; the protocol will not do it.
Encryption and MLLP
Plain MLLP travels in cleartext. The original specification predates the routine use of TLS by years, and many older deployments still run unencrypted on private hospital networks. This is not safe outside a controlled network — HL7v2 messages carry protected health information, and cleartext on any path that a hospital does not fully control is a problem.
The standard remedy is to wrap the TCP connection in TLS. The framing is unchanged: the same start byte, the same end sequence, the same payload bytes — they just travel over a TLS-encrypted socket instead of a plain one. Most modern receivers support both; some require client certificates as a second layer of authentication, which fits naturally because the connection is long-lived and the cost of negotiation is paid once.
A separate refinement, sometimes called MLLPv2 (or enhanced MLLP), adds explicit acknowledgment at the frame level: each frame is followed by a small <ACK> or <NAK> byte indicating whether the framing was understood, before the application-level HL7v2 ack is sent. The frame-level ack is rare in production — most deployments have settled on plain MLLP over TLS — but it appears in some specifications for reliable delivery.
Where MLLP fits, and where it does not
MLLP is the right answer when two systems on the same network want to exchange HL7v2 messages with low latency, high volume, and very little protocol overhead. It is what hospital integration buses are built on and what the standard's authors had in mind.
It is not the right answer everywhere. Three other transports show up in practice.
The first is HL7v2 over HTTP, where each message is the body of a POST request. This fits modern API gateways, load balancers, and observability stacks that already speak HTTP. It costs more per message — the connection is rarely reused, the headers are heavier than MLLP's three bytes, and the request/response cycle adds round-trips — but it slots into infrastructure that does not understand long-lived TCP.
The second is a message queue (Kafka, RabbitMQ, AWS SQS, and similar). The messages are queued by the source system and consumed by the destination at its own pace. The framing is the queue's; HL7v2 sits inside the message body. This decouples sender and receiver, which is useful when the destination is not always reachable, but it loses the immediate ack that MLLP provides.
The third is file drop, where messages are written to a shared filesystem in batches and the destination polls. This is the lowest-tech option and remains common in older deployments, particularly between systems that do not share a network.
The choice between these is rarely greenfield. Most of the time the partner system has already decided, and the integrator builds to whatever the partner expects. The choice is, in practice, what the partner says.
Trade-offs
MLLP is the protocol HL7v2 has, not the protocol it would have if designed today. It carries that age as both a strength and a weakness.
The strength is its smallness. Three bytes of framing and a TCP connection are all there is to learn; an implementation can be written in an afternoon and interoperate with thirty-year-old systems unchanged. There is no version negotiation, no content type, no schema discovery — and consequently no place for those things to go wrong.
The weakness is the same smallness. There is no built-in authentication: the connection is open to whoever can reach the port. There is no reliability beyond what TCP provides: a message acknowledged at the application level may still be lost if the receiving process crashes between writing the ack and persisting the work. There is no observability: the protocol is a stream of bytes that a network sniffer reads only with help. Each of these gaps is closed in practice — TLS for authentication, application-level idempotency for reliability, structured logging for observability — but the protocol itself does not help.
The reason MLLP persists, despite the gaps, is the same reason HL7v2 persists. Replacing a working protocol that connects every system in a hospital is expensive, and the new protocol has to be measurably better at the things that already work. MLLP's competitors — HL7v2 over HTTP, FHIR over REST, message queues — are better in some ways and worse in others, and none has displaced it. The honest summary is that MLLP is good enough at what it does to outlast the things designed to replace it.
Further reading
- Message flow — how MLLP fits into the wider exchange between source and destination.
- Acknowledgments — what arrives in the ack frame.
- Interface engines — the middleware layer that usually terminates MLLP on each side.
- HL7 — Minimal Lower-Layer Protocol — the specification, in the standard's transport appendix.