The Message Descriptor (MQMD) is the envelope every IBM MQ message carries through put, get, channels, and dead-letter handling. Application bytes live in a separate buffer; MQMD tells the queue manager and receivers how to interpret those bytes, how long to keep them, whether to log them to disk, and how to route replies. Beginners often stuff business data into the wrong place or leave Format and CodedCharSetId default while sending JSON—downstream COBOL sees garbage. Advanced integration uses UserIdentifier, PutApplName, and PutDate for audit. This tutorial walks through major MQMD fields, how MQPUT supplies them versus how MQGET returns them, persistence and priority interactions, request/reply addressing with ReplyToQ and ReplyToQMgr, expiry, message type, reporting options, and encoding pitfalls between ASCII Linux and EBCDIC z/OS partners.
MQMD is defined in cmqc.h (C) and equivalent headers in COBOL copybooks and Java MQMessage. Initialize with MQMD_DEFAULT before MQPUT so unused fields are zeroed. On MQGET, the queue manager overwrites fields to describe the message read—your input mask can request specific fields with MQGMO properties per API. Length of MQMD is fixed; variable data like accounting tokens fit in defined char arrays with IBM length constants.
12345678910MQMD md = {MQMD_DEFAULT}; memcpy(md.Format, MQFMT_STRING, (size_t)MQ_FORMAT_LENGTH); md.Persistence = MQPER_PERSISTENT; md.Priority = 5; md.Expiry = MQEI_UNLIMITED; memcpy(md.MsgId, MQMI_NONE, sizeof(md.MsgId)); memcpy(md.CorrelId, MQCI_NONE, sizeof(md.CorrelId)); strncpy(md.ReplyToQ, "ORDER.REPLY", sizeof(md.ReplyToQ)); strncpy(md.ReplyToQMgr, "QM1", sizeof(md.ReplyToQMgr));
| Field | Purpose | Put / Get |
|---|---|---|
| Format | Payload type (STRING, NONE, custom) | Set on put; read on get |
| MsgId | Unique message identity | Optional input; output on get |
| CorrelId | Link related messages | Set for matching gets |
| Persistence | Persistent vs not | Affects restart survival |
| Priority | Relative delivery order hint | Higher first when supported |
| ReplyToQ / ReplyToQMgr | Reply routing | Client sets; server reads |
| Encoding / CodedCharSetId | Character set of payload | Use with MQGMO_CONVERT |
| Expiry | Lifetime limit | Message discarded when expired |
| MsgType | Request, reply, report, datagram | Drives report generation |
MsgId is 24 bytes—often displayed hex in support tools. MQPMO_NEW_MSG_ID asks the queue manager to assign one; essential when applications cannot guarantee uniqueness. CorrelId is also 24 bytes; default MQCI_NONE means no correlation. Request/reply: client saves MsgId from request; server sets reply CorrelId to that value; client MQGET with MATCH_CORREL_ID on reply queue. Fire-and-forget may leave both as NONE. Duplicate detection systems store MsgId in a database to reject replays.
MQPER_PERSISTENT messages survive queue manager restart when logged per queue and system policy. MQPER_NOT_PERSISTENT is faster for telemetry where loss is acceptable. Priority 0–9 (platform defaults documented by IBM) influences order when multiple messages wait; not a substitute for separate priority queues in all workloads. Compare with DEFPSIST on the queue object when MQMD leaves persistence default.
MQMD is everything written on the outside of the package: who sent it, whether it is registered mail, which mailbox the return label uses, and whether the inside is a letter or a photo (Format).
ReplyToQ names the queue for answers; ReplyToQMgr names the queue manager if different from the target of the put. Empty ReplyToQMgr often means same queue manager as connection. Cross-site reply requires reachable queue manager names in clusters or explicit channel paths. Server must have put authority to the reply queue—2035 on reply put is a common integration bug.
MQFMT_STRING expects textual data with CodedCharSetId such as UTF-8 (1208) or EBCDIC on mainframe. MQGMO_CONVERT on get can translate to the application's desired encoding. MQFMT_NONE says opaque binary—length-delimited COBOL copybooks or protobuf bytes. Partners must agree custom format names like "MYPAY/v2" in Format field for routing in message-driven beans.
Expiry is in tenths of a second from put time; MQEI_UNLIMITED means no expiry. Expired messages are discarded on get or moved per configuration. MsgType MQMT_REQUEST expects reply; MQMT_REPLY pairs with correl; MQMT_DATAGRAM is one-way. Report messages (MQMT_REPORT) support COA and COD feedback when Report options set—advanced but appears in audit trails.
UserIdentifier and PutApplName record who put the message when context is passed or adopted. PutDate and PutTime stamp insertion. Used in compliance and poison message investigation. MQPMO_SET_IDENTITY_CONTEXT requires authority—do not spoof without controls.
JMS and integration fabrics often add MQRFH2 headers before payload. MQMD still describes the message; RFH2 carries folders for properties. See the MQRFH2 tutorial for header chains; total message length includes all parts.
MQMD is the label on your package that says who it is for, whether it is important enough to save in a safe, and where to send the answer back.
Fill MQMD fields for a request message to PAYMENTS.IN with reply queue CLIENT.REPLY on QM_CLIENT.
Explain server steps to set CorrelId on the reply from saved request MsgId.
Compare persistent versus non-persistent MQMD for audit log versus metrics stream.
1. ReplyToQ in MQMD tells:
2. MQPER_PERSISTENT means:
3. CorrelId often matches:
4. MQMD is NOT: