Modbus Function Codes: Complete Reference Cheat Sheet

ModbusModbus function codesModbus referenceModbus exceptionsholding registers
May 22, 2026|8 min read

Modbus function codes are single-byte values in the PDU that tell the server what operation to perform on what data type. The four most-used codes are FC01 (Read Coils), FC02 (Read Discrete Inputs), FC03 (Read Holding Registers), and FC04 (Read Input Registers); the most-used writes are FC05, FC06, FC15, and FC16. When a server cannot complete a request, it returns the requested function code with the high bit set (function code + 0x80) followed by a one-byte exception code. Treat every other function code as optional — many BAS gateways implement only a subset.

When You Need This Reference

You're reading a register map for a chiller, VFD, or energy meter. The vendor lists addresses like "40001" or "4x0001" for read-only kWh totals, and the supervisor driver asks you to choose a function code. Or your Modbus TCP client returns response 0x83 0x02 and you need to know what that means before opening a ticket. Or you're writing a Python script and need to pick between read_holding_registers() and read_input_registers() without guessing.

The Modbus Application Protocol Specification (Modbus.org, V1.1b3) defines the full set. Most BAS field devices and gateways implement maybe six to ten of them. Everything below is from that public spec and the worded examples that accompany it.

The Four Modbus Data Tables

Function codes only make sense in relation to the data tables. Every Modbus server presents up to four logical address spaces, each with its own access rules:

The convention you'll see in vendor docs — "1xxxxx", "0xxxxx", "3xxxxx", "4xxxxx" — is a documentation aid that maps to those four tables. The byte that actually goes on the wire is the function code plus a zero-based address. Off-by-one between the documented reference (1-based) and the on-wire address (0-based) is the single most common Modbus integration mistake. See the Modbus register map reading guide for the addressing translation in detail.

Standard Function Codes (Public Spec)

Codes 1–127 are public function codes defined by Modbus.org. The table below lists every one that has standard semantics. Hex values are shown because most diagnostic tools display them that way.

FC (dec)HexNameData tableAccess
010x01Read CoilsCoilsRead
020x02Read Discrete InputsDiscrete InputsRead
030x03Read Holding RegistersHolding RegistersRead
040x04Read Input RegistersInput RegistersRead
050x05Write Single CoilCoilsWrite (1)
060x06Write Single RegisterHolding RegistersWrite (1)
070x07Read Exception Status(server-defined)Read, serial line only
080x08Diagnostics(server-defined)Various, serial line only
110x0BGet Comm Event Counter(counter)Read, serial line only
120x0CGet Comm Event Log(log)Read, serial line only
150x0FWrite Multiple CoilsCoilsWrite (N)
160x10Write Multiple RegistersHolding RegistersWrite (N)
170x11Report Server ID(server info)Read, serial line only
200x14Read File RecordFile recordsRead
210x15Write File RecordFile recordsWrite
220x16Mask Write RegisterHolding RegistersRead-modify-write
230x17Read/Write Multiple RegistersHolding RegistersAtomic R+W
240x18Read FIFO QueueHolding RegistersRead
430x2BEncapsulated Interface Transport (MEI)Sub-function dependentVarious

Note that codes 07, 08, 11, 12, and 17 are defined only for serial-line Modbus (RTU/ASCII). They are not used on Modbus TCP. The Modbus.org spec explicitly excludes them from the TCP/IP mapping.

Codes 65–72 and 100–110 are reserved as user-defined ranges. Vendors sometimes use them for device-specific operations (firmware update, calibration, factory reset). Treat anything outside the table above as non-portable and check the vendor's manual.

Read Function Codes: Worked Examples

FC03 vs FC04 — the most common confusion

Both read 16-bit registers. The difference is which table they target:

If a device documents a value at "30005", use FC04 with zero-based address 0x0004. If it documents "40005", use FC03 with zero-based address 0x0004. Many devices put the same value in both tables for compatibility, but you cannot count on that.

FC03 request and response on the wire

Reading 2 holding registers starting at address 0x006B (decimal 107, which corresponds to documented register 40108 in 1-based notation):

Request PDU:
  Function code:  03
  Start address:  00 6B
  Quantity:       00 02

Response PDU (success):
  Function code:  03
  Byte count:     04        (= 2 registers × 2 bytes)
  Register data:  XX XX YY YY

Response PDU (exception):
  Function code:  83        (= 03 with high bit set)
  Exception code: 02        (Illegal Data Address)

The maximum quantity in a single FC03 or FC04 is 125 registers per the spec. FC01 and FC02 cap at 2000 bits. Asking for more is the second most common cause of an exception code 03 (Illegal Data Value).

Write Function Codes: Worked Examples

FC05 Write Single Coil

A single-coil write uses two magic values: 0xFF00 means ON, 0x0000 means OFF. Any other value is invalid. The server echoes the request back on success:

Request PDU:
  Function code:  05
  Coil address:   00 AC
  Output value:   FF 00      (ON)

Response PDU (success):
  Function code:  05
  Coil address:   00 AC
  Output value:   FF 00

FC06 vs FC16 — single vs multiple registers

FC06 writes exactly one 16-bit register. FC16 writes a contiguous range, up to 123 registers per request. Use FC16 for any multi-register value (32-bit floats, 32-bit integers, multi-word strings) so the two words land in the same transaction. Splitting a 32-bit float across two FC06 writes can produce a half-updated value if the server processes them between requests.

FC22 Mask Write Register — atomic bit set/clear

FC22 lets a client set or clear specific bits in a holding register without a separate read-modify-write. The server computes:

new_value = (current AND and_mask) OR (or_mask AND (NOT and_mask))

That is the spec's exact algebra (Modbus Application Protocol V1.1b3, section 6.16). Useful when several clients can write to the same status word and you only want to change one bit. Support is patchy on field devices — check before relying on it.

FC23 Read/Write Multiple Registers

FC23 is one request that writes a range and reads a (possibly different) range atomically. The write happens before the read, so the response can include the just-written values. Use it when a command and its acknowledgment live in different registers and you need them in lockstep.

Exception Responses

When a server cannot complete a request, it returns the function code with the high bit set and a one-byte exception code. So FC03 fails as 0x83, FC16 fails as 0x90, etc. The standard exception codes are:

Code (hex)NameMeaning
0x01Illegal FunctionThe server does not support this function code.
0x02Illegal Data AddressThe address (or address + quantity) is not valid for this server.
0x03Illegal Data ValueA value in the request is not allowed (e.g., quantity exceeds the per-FC maximum).
0x04Server Device FailureUnrecoverable error while processing the request.
0x05AcknowledgeRequest accepted but will take time; client should poll with Read Exception Status or Diagnostics.
0x06Server Device BusyServer is processing a long-running command; retry later.
0x08Memory Parity ErrorUsed with FC20/FC21 file record operations.
0x0AGateway Path UnavailableA gateway misrouted the request (no path to the target).
0x0BGateway Target Device Failed To RespondThe gateway reached its serial side but the downstream device did not answer.

Codes 0x0A and 0x0B are the two you'll see most often when a Modbus TCP gateway sits between a supervisor and an RS-485 trunk. They mean the problem is on the serial side, not the IP side — check baud rate, parity, Unit ID, and wiring before suspecting the gateway. The Modbus RTU troubleshooting checklist walks through that diagnosis.

Encapsulated Interface Transport (FC43)

FC43 carries sub-functions identified by a Modbus Encapsulated Interface (MEI) type. The one that matters in the field is MEI Type 14 (0x0E) — Read Device Identification. It returns vendor name, product code, and revision strings — useful when you've inherited a panel with no labels and need to identify what's on the wire. Not every device implements it; expect exception code 0x01 if it's missing.

Common Pitfalls

When to Escalate

If you've confirmed the right function code, the right address, and a quantity within the spec's limit, and you're still getting exception 0x02 or 0x03, the issue is on the device side. Pull the vendor's register map and check whether the address range is gated by a license, a mode (run vs configuration), or a writable-only-when-stopped condition (common on VFDs). If exception 0x0B (Gateway Target Device Failed To Respond) appears intermittently, capture serial-side traffic at the gateway — the problem is almost always electrical or a Unit ID mismatch, not the function code.

For deeper protocol-level questions, the Modbus.org specifications are the authoritative source and are freely available.

Source Attribution

Additional review and field validation by SiteConduit.

Modbus function codesModbus referenceModbus exceptionsholding registerscoils

Was this article helpful?

Related Articles

Need to do this remotely? SiteConduit supports Modbus remote access with the same protocol-level controls as BACnet. Join the waitlist.

SC

SiteConduit Technical Team

Idea Networks Inc.

SiteConduit builds managed remote access for building automation. Our knowledge base is maintained by BAS professionals with hands-on experience deploying and troubleshooting BACnet, Niagara, Modbus, and Facility Explorer systems.