Modbus Function Codes — Complete Reference

Every Modbus request begins with two bytes: the slave address and a function code (FC). The function code tells the slave device exactly what operation to perform — read coils, write a register, read input values, and so on. If you pick the wrong function code, you get Exception Code 01 (Illegal Function). If you pick the right one but address the wrong register type, you get garbage data or Exception Code 02.

The standard function codes are defined in the Modbus Application Protocol Specification maintained by the Modbus Organization. In practice, most devices only implement a subset of these codes. The eight function codes covered on this page handle the vast majority of real-world Modbus communication.

Key Concept

Function codes map directly to register types. Coils and Discrete Inputs are 1-bit values. Holding Registers and Input Registers are 16-bit values. Using the wrong function code for a register type is the single most common cause of Exception Code 01.

Function Code Summary Table

FCHexNameData TypeAccessClassic Address Range
010x01Read Coils1-bit (boolean)Read00001 – 09999
020x02Read Discrete Inputs1-bit (boolean)Read-only10001 – 19999
030x03Read Holding Registers16-bit (word)Read/Write40001 – 49999
040x04Read Input Registers16-bit (word)Read-only30001 – 39999
050x05Write Single Coil1-bit (boolean)Write00001 – 09999
060x06Write Single Register16-bit (word)Write40001 – 49999
150x0FWrite Multiple CoilsN × 1-bitWrite00001 – 09999
160x10Write Multiple RegistersN × 16-bitWrite40001 – 49999

FC01 — Read Coils

Reads the ON/OFF status of discrete coils in the slave. Coils are single-bit outputs that your master can both read and write. Think of them as digital output flags — relay states, valve positions, motor run/stop commands.

Request Frame (RTU)

Slave Addr | FC   | Start Address | Quantity    | CRC
1 byte     | 0x01 | 2 bytes (Hi-Lo)| 2 bytes    | 2 bytes

Response Frame

Slave Addr | FC   | Byte Count | Coil Data   | CRC
1 byte     | 0x01 | 1 byte     | N bytes     | 2 bytes

Coil data is packed as bits, LSB first. If you request 10 coils, you get 2 bytes back (16 bits, with 6 unused bits padded with zeros).

Example: Read 8 coils starting at address 0 from slave 1

Request:  01 01 00 00 00 08 3D CC
Response: 01 01 01 6B 11 C8

Breakdown of response data byte 0x6B = 0110 1011:
  Coil 0 = ON  (bit 0)
  Coil 1 = ON  (bit 1)
  Coil 2 = OFF (bit 2)
  Coil 3 = ON  (bit 3)
  Coil 4 = OFF (bit 4)
  Coil 5 = ON  (bit 5)
  Coil 6 = ON  (bit 6)
  Coil 7 = OFF (bit 7)

Common use cases: Reading the status of relays on a PLC output module, checking whether a digital output is energised, polling a bank of indicator lamp states.

FC02 — Read Discrete Inputs

Reads the ON/OFF status of discrete input contacts. These are read-only single-bit values representing physical digital inputs — limit switches, pushbuttons, proximity sensors, door contacts. The frame format is identical to FC01, but the register space is different.

Request Frame (RTU)

Slave Addr | FC   | Start Address | Quantity    | CRC
1 byte     | 0x02 | 2 bytes (Hi-Lo)| 2 bytes    | 2 bytes

Response Frame

Slave Addr | FC   | Byte Count | Input Data  | CRC
1 byte     | 0x02 | 1 byte     | N bytes     | 2 bytes

Example: Read 4 discrete inputs starting at address 0 from slave 2

Request:  02 02 00 00 00 04 79 FA
Response: 02 02 01 05 A1 88

Data byte 0x05 = 0000 0101:
  Input 0 = ON  (bit 0) - e.g. limit switch closed
  Input 1 = OFF (bit 1)
  Input 2 = ON  (bit 2) - e.g. pushbutton pressed
  Input 3 = OFF (bit 3)

Common use cases: Monitoring limit switches, reading door contacts or safety interlocks, checking pushbutton states, polling sensor digital outputs.

FC03 — Read Holding Registers

This is the most widely used function code in Modbus. It reads one or more 16-bit holding registers. Holding registers are the workhorse of Modbus — they store configuration parameters, setpoints, measurement values, and anything else the device exposes. They are readable and writable (via FC06 or FC16).

Request Frame (RTU)

Slave Addr | FC   | Start Address | Quantity    | CRC
1 byte     | 0x03 | 2 bytes (Hi-Lo)| 2 bytes    | 2 bytes

Response Frame

Slave Addr | FC   | Byte Count | Register Data | CRC
1 byte     | 0x03 | 1 byte     | N x 2 bytes   | 2 bytes

Each register is 2 bytes, big-endian (high byte first). If you request 3 registers, you get 6 data bytes back.

Example: Read 2 holding registers starting at address 0 from slave 1

Request:  01 03 00 00 00 02 C4 0B
Response: 01 03 04 01 F4 00 64 FA 6D

Register 0 = 0x01F4 = 500  (e.g. voltage: 500 = 50.0V with scale factor /10)
Register 1 = 0x0064 = 100  (e.g. current: 100 = 10.0A with scale factor /10)

Common use cases: Reading energy meter values (voltage, current, power, kWh), reading PLC holding registers, fetching device configuration parameters, reading setpoints.

FC03 vs FC04

When a device manual says "read register 40001," that usually means FC03 at address 0. When it says "read register 30001," that means FC04 at address 0. If FC03 returns Exception 01, try FC04 — the device may have implemented measurements as input registers rather than holding registers.

FC04 — Read Input Registers

Reads one or more 16-bit input registers. Input registers are read-only — they typically represent live measurements or status values that the device updates internally. The frame format is identical to FC03, just with function code 0x04.

Request Frame (RTU)

Slave Addr | FC   | Start Address | Quantity    | CRC
1 byte     | 0x04 | 2 bytes (Hi-Lo)| 2 bytes    | 2 bytes

Response Frame

Slave Addr | FC   | Byte Count | Register Data | CRC
1 byte     | 0x04 | 1 byte     | N x 2 bytes   | 2 bytes

Example: Read 1 input register at address 5 from slave 3

Request:  03 04 00 05 00 01 21 E8
Response: 03 04 02 01 A4 99 CA

Register 5 = 0x01A4 = 420  (e.g. temperature: 420 = 42.0 degrees C)

Common use cases: Reading temperature sensor values, live measurements from energy meters (some meters use FC04 for measurements and FC03 for configuration), ADC conversion results from I/O modules.

FC05 — Write Single Coil

Forces a single coil to ON or OFF. The value field must be either 0xFF00 for ON or 0x0000 for OFF. Any other value triggers Exception Code 03 (Illegal Data Value). The response is an exact echo of the request.

Request Frame (RTU)

Slave Addr | FC   | Coil Address  | Value       | CRC
1 byte     | 0x05 | 2 bytes (Hi-Lo)| 2 bytes    | 2 bytes

Response Frame

Slave Addr | FC   | Coil Address  | Value       | CRC
1 byte     | 0x05 | 2 bytes       | 2 bytes     | 2 bytes
(exact echo of request)

Example: Turn ON coil 0 on slave 1

Request:  01 05 00 00 FF 00 8C 3A
Response: 01 05 00 00 FF 00 8C 3A  (echo)

Example: Turn OFF coil 0 on slave 1

Request:  01 05 00 00 00 00 CD CA
Response: 01 05 00 00 00 00 CD CA  (echo)

Common use cases: Toggling a relay on a remote I/O module, activating a solenoid valve, triggering a reset command, starting or stopping a motor via PLC digital output.

Only Two Valid Values

FC05 only accepts 0xFF00 (ON) and 0x0000 (OFF). Sending 0x0001 or 0x00FF will cause Exception Code 03 on a compliant device. Some non-compliant devices accept 0x0001 as ON, but don't rely on this.

FC06 — Write Single Register

Writes a single 16-bit value to a holding register. Used for setting configuration parameters, changing setpoints, or writing a control value. Like FC05, the response is an exact echo of the request.

Request Frame (RTU)

Slave Addr | FC   | Register Addr | Value       | CRC
1 byte     | 0x06 | 2 bytes (Hi-Lo)| 2 bytes    | 2 bytes

Response Frame

Slave Addr | FC   | Register Addr | Value       | CRC
1 byte     | 0x06 | 2 bytes       | 2 bytes     | 2 bytes
(exact echo of request)

Example: Write value 9600 (0x2580) to register 3 on slave 1

Request:  01 06 00 03 25 80 78 36
Response: 01 06 00 03 25 80 78 36  (echo)

This might set the device's baud rate register to 9600.

Common use cases: Setting a device's slave address, configuring baud rate, writing a temperature setpoint, adjusting PID parameters, setting alarm thresholds on energy meters.

FC15 (0x0F) — Write Multiple Coils

Forces multiple consecutive coils in a single request. The coil values are bit-packed, LSB first, the same format as FC01 response data. Useful when you need to set a bank of digital outputs atomically rather than one at a time with FC05.

Request Frame (RTU)

Slave Addr | FC   | Start Address | Quantity    | Byte Count | Coil Data | CRC
1 byte     | 0x0F | 2 bytes       | 2 bytes     | 1 byte     | N bytes   | 2 bytes

Response Frame

Slave Addr | FC   | Start Address | Quantity    | CRC
1 byte     | 0x0F | 2 bytes       | 2 bytes     | 2 bytes

Example: Write coils 0-7 on slave 1 (turn ON coils 0, 1, 3, 5)

Request:  01 0F 00 00 00 08 01 2B BE A6
Response: 01 0F 00 00 00 08 54 0D

Data byte 0x2B = 0010 1011:
  Coil 0 = ON  (bit 0)
  Coil 1 = ON  (bit 1)
  Coil 2 = OFF (bit 2)
  Coil 3 = ON  (bit 3)
  Coil 4 = OFF (bit 4)
  Coil 5 = ON  (bit 5)
  Coil 6 = OFF (bit 6)
  Coil 7 = OFF (bit 7)

Common use cases: Setting an entire bank of relay outputs at once, initialising all digital outputs on a PLC module during startup, batch-writing output states for coordinated control.

FC16 (0x10) — Write Multiple Registers

Writes to multiple consecutive holding registers in a single request. This is essential for writing 32-bit float values (which span two consecutive 16-bit registers) and for batch configuration updates. Most devices support writing up to 123 registers per request (the maximum that fits in a single Modbus RTU frame).

Request Frame (RTU)

Slave Addr | FC   | Start Address | Quantity    | Byte Count | Register Data | CRC
1 byte     | 0x10 | 2 bytes       | 2 bytes     | 1 byte     | N x 2 bytes   | 2 bytes

Response Frame

Slave Addr | FC   | Start Address | Quantity    | CRC
1 byte     | 0x10 | 2 bytes       | 2 bytes     | 2 bytes

Example: Write two registers (a 32-bit float) starting at address 10 on slave 1

Request:  01 10 00 0A 00 02 04 42 C8 00 00 2B 05
Response: 01 10 00 0A 00 02 01 C9

Register 10 = 0x42C8, Register 11 = 0x0000
As a 32-bit float (Big Endian): 100.0

Common use cases: Writing 32-bit float setpoints (temperature, pressure), batch-writing PLC configuration, writing multi-register values like date/time, updating firmware data blocks.

All Function Codes

No Manual Hex Calculation Needed

ModBus Pro supports all standard function codes out of the box. Select your register type and the correct FC is automatically chosen — no manual hex calculation needed. Raw frame view shows every byte for debugging.

Download Free

Exception Codes Quick Reference

When a slave cannot fulfil a request, it returns an exception response. The function code in the response has bit 7 set (e.g., FC03 becomes 0x83), followed by an exception code byte.

CodeHexNameCommon Trigger
010x01Illegal FunctionDevice does not support this function code (e.g., using FC03 when only FC04 is implemented)
020x02Illegal Data AddressRegister address does not exist on this device, or address + quantity exceeds valid range
030x03Illegal Data ValueValue in write request is out of range (e.g., FC05 with a value other than 0x0000 or 0xFF00)
040x04Slave Device FailureUnrecoverable internal error on the slave while processing the request
050x05AcknowledgeSlave accepted request but needs time to process (e.g., firmware update, EEPROM write)
060x06Slave Device BusySlave is currently processing another long-duration command; retry after a delay

For detailed troubleshooting of each exception code, see the dedicated guides: Exception 01 (Illegal Function) and Exception 02 (Illegal Data Address).

Register Type Mapping & The 40001 Offset

The classic Modbus addressing convention uses a numeric prefix to indicate the register type:

PrefixRangeRegister TypeFunction Codes
0xxxx00001 – 09999Coils (1-bit, R/W)FC01 (read), FC05 (write one), FC15 (write many)
1xxxx10001 – 19999Discrete Inputs (1-bit, read-only)FC02 (read)
3xxxx30001 – 39999Input Registers (16-bit, read-only)FC04 (read)
4xxxx40001 – 49999Holding Registers (16-bit, R/W)FC03 (read), FC06 (write one), FC16 (write many)

The 40001 Confusion

A device manual says "read register 40001." What Modbus address do you actually send on the wire? The answer is address 0 using function code 03. The "4" prefix just tells you this is a holding register, and the numbering starts at 1 (not 0). So:

  • 40001 in documentation = FC03, address 0x0000 on the wire
  • 40100 in documentation = FC03, address 0x0063 (99 decimal) on the wire
  • 30001 in documentation = FC04, address 0x0000 on the wire
Tool Differences

Not all Modbus tools handle this offset the same way. Some expect you to enter the wire address (0-based), while others expect the documentation address (40001-style). If you enter 40001 in a tool that expects wire addresses, you'll be reading address 40001 (0x9C41) — almost certainly an invalid register. Check your tool's documentation to know which convention it uses.

For a deep dive into addressing, see the Register Offset guide.