Troubleshooting Modbus TCP Server Connection on S7-1200 PLC

David Krause13 min read
ModbusSiemensTroubleshooting
Licensed PE Working through this on a live machine? A Maine-licensed engineer can take it from here — included with IMD hardware, by the hour for everything else. Book an engineer

Troubleshooting Modbus TCP Server Connection on S7-1200 PLC

When commissioning an S7-1200 CPU as a Modbus TCP server and connecting it to a PC-based test client, two symptoms dominate the field: (1) the TCP session establishes briefly while the instruction STATUS reports 16#7002 and then drops the moment STATUS returns 16#0000, and (2) the client can read holding registers but writes to the same registers silently fail. This article consolidates the official Siemens instruction behavior, the relevant STATUS codes, and the configuration settings that resolve both issues without changing the topology.

1. Problem Overview

A typical symptom chain reported during commissioning:

  1. The PC client (e.g., SimplyModbus, Modbus Poll) successfully opens a TCP session on port 502 of the S7-1200.
  2. On the PLC side, the MB_SERVER instance DB shows STATUS = 16#7002 (job processing) and the client can perform one or more transactions.
  3. Once STATUS returns to 16#0000, the client loses the connection, and reconnect attempts fail until the PLC program is re-downloaded.
  4. Read FC03/FC04 operations succeed, but FC06/FC16 write attempts either time out or return an exception code 04 (slave device failure) on the client.

These symptoms are almost always traced to one of three root causes: the MB_SERVER instance is not being called cyclically, the holding-register pointer block has been optimized (which blocks Modbus access), or the TSAP / port assignment on the S7-1200 conflicts with another service.

2. MB_SERVER and MB_CLIENT Instruction Roles

The SIMATIC S7-1200 supports Modbus TCP natively through the PROFINET interface. Two primary instructions are used:

Instruction Role Direction Port (default)
MB_CLIENT Modbus TCP client Initiates connection to a remote server Any (configured per connection)
MB_SERVER Modbus TCP server Listens and answers client requests 502

For the scenario in the source post, the S7-1200 acts as the server and the PC is the client. The full instruction reference is published in the SIMATIC S7-1200 Programmable Controller Manual Collection, specifically the Modbus TCP Instructions (MB_CLIENT, MB_SERVER) section in the Siemens TIA Portal documentation portal.

Architectural note: Modbus TCP on the S7-1200 rides on top of the PROFINET interface. No CP (communication processor) module is required; the standard Ethernet port of the CPU is used. Each MB_SERVER call consumes one open connection resource from the CPU's internal connection table. The S7-1200 supports a maximum of eight open Modbus connections per CPU, shared between MB_CLIENT and MB_SERVER.

3. Prerequisites: Firmware and TIA Portal Versions

Component Minimum Version Notes
S7-1200 CPU firmware V4.0 MB_SERVER instruction requires V4.0 or later. Firmware V4.2+ recommended for stable reconnection behavior.
TIA Portal (engineering) V13 SP1 V15.1 or later recommended for the current instruction set.
SIMATIC Modbus TCP library Delivered with TIA Portal Instructions are in the "Communication > Other" or "Communication > Modbus TCP" task card.
Number of Modbus connections Up to 8 per CPU Includes both client and server connections. Configured in PLC properties under "Modbus TCP connection count".

Verify the CPU firmware with TIA Portal: Online > Accessible devices > right-click CPU > Online & diagnostics > Diagnostics. The firmware version is reported under "Module information".

4. Configuring MB_SERVER as a Modbus TCP Server

4.1 Create a Holding Register Data Block

  1. In the project tree, select Add new block > Data block (DB).
  2. Uncheck Optimized block access. Optimized DBs cannot be addressed by Modbus function codes because the byte offset is not deterministic.
  3. Define the registers. For example:

DATA_BLOCK "ModbusRegisters"
{ S7_Optimized_Access := 'FALSE' }
VERSION : 0.1
NON_RETAIN
  STRUCT
    HoldingReg : ARRAY[0..99] OF WORD;   // 100 holding registers, FC03/FC06/FC16
    InputReg   : ARRAY[0..99] OF WORD;   // 100 input registers, FC04
  END_STRUCT;
END_DATA_BLOCK
  1. Note the absolute byte offset of HoldingReg[0]. In a non-optimized DB, the offset is the sum of preceding static data; here, HoldingReg starts at offset 0.

4.2 Insert and Wire MB_SERVER

  1. Open the main OB (typically OB1) and drag MB_SERVER from the task card into a network.
  2. Create an instance DB when prompted (e.g., MB_SERVER_DB).
  3. Wire the input parameters:
Input Typical Value Purpose
DISCONNECT FALSE (M0.0) 0 = accept connection, 1 = terminate active connection.
CONNECT_ID 1 (WORD) Unique connection identifier. Must not collide with any other MB_CLIENT/active connection in the project.
IP_OCTET_1..4 0.0.0.0 For a server, leave all four octets at 0 to accept any client IP. Setting a specific value restricts the server to a single remote IP.
IP_PORT 502 TCP port. The standard Modbus port is 502.
MB_HOLD_REG P#DB20.DBX0.0 WORD 100 Pointer to the start and length of the holding-register area (must be a non-optimized DB).
  1. Ensure MB_SERVER is called every scan cycle. Placing it in OB1 is the most common and reliable approach. Do not call it conditionally (gated by a flag or inside a slow OB), or the server will appear to "stop responding" the moment the condition is false.
Cyclic call requirement: MB_SERVER is a background instruction that must be invoked once per PLC cycle. If the call is moved into an event-driven OB (such as a time-of-day interrupt) or skipped by a conditional rung, the TCP listener stalls and the client connection drops as soon as STATUS cycles through 16#7002 to 16#0000. This is the single most common cause of the "works once, then drops" symptom described in the source post.

5. STATUS Code Reference Table

The following STATUS values are documented for MB_SERVER and MB_CLIENT. Codes are 16-bit words; values are hexadecimal. Refer to the in-editor Help panel for the active CPU firmware's full list.

STATUS Meaning Action
16#0000 No error. Instruction executed successfully or no active job. Informational. If the connection drops in this state, check the call frequency (see §4.2) and DISCONNECT input.
16#7000 No call active / no job in progress. Normal state when no client is connected.
16#7001 First call after connection established; job being processed. Informational.
16#7002 Subsequent call; job in process. Informational. The source post correctly identifies this as the "busy" code, not an error.
16#8188 Invalid mode (parameter assignment mismatch). Re-check MB_MODE/MB_DATA_ADDR/MB_DATA_LEN on MB_CLIENT; for the server, verify MB_HOLD_REG pointer.
16#8380 Invalid ID parameter (CONNECT_ID out of range). Use a WORD in range 0..255 for the S7-1200.
16#8381 Invalid connection ID (already in use). Each MB_SERVER / MB_CLIENT instance must have a unique CONNECT_ID.
16#8382 Connection ID already in use as a different role. Same ID is used twice; renumber one instance.
16#8383 No more connection resources. Reduce number of simultaneous Modbus connections, or check CPU connection-resource count (max 8 for S7-1200).
16#80C8 The remote terminal is not responding within the timeout window. Verify cabling, IP address, and that the client is using the same port. Increase the timeout on MB_CLIENT if the server is slow.
16#80D2 Server connection cannot be established (TSAP or port mismatch). Confirm the server's port and any TSAP settings; see §6.2.
16#80D4 Server connection terminated by remote. Client closed the socket. Investigate the client software.
16#80D5 Server connection actively terminated (DISCONNECT = 1). Check the logic driving the DISCONNECT input.
16#80D6 Remote party terminated the connection. Client closed; check client logs.
16#80D7 Connection lost (timeout, cable break). Verify physical layer; check switch, cabling, and port LEDs on the S7-1200.
16#80D8 Connection rejected by remote. Server rejected the client. Verify IP filtering on the server (IP_OCTET_1..4).

6. PC Test Client Options for S7-1200

6.1 Recommended Test Clients

Software Vendor License Function Code Support Notes
Modbus Poll Witte Software Commercial; time-limited trial FC01..FC06, FC15, FC16, FC23 Industry standard for lab validation. Provides transaction logs and exception code display.
SimplyModbus TCP Client WinTech Free for limited session time FC03, FC06, FC16 Lightweight, no install required. Useful for quick field validation.
Modbus Tools (modbus tools.com) Independent developer Free FC01..FC16 GUI client and master simulator. Good for batch scripting.
QModMaster open source Free (GPL) FC01..FC16 Cross-platform; integrates with the libmodbus library.

6.2 Client Connection Settings to Match the S7-1200

  • Remote IP: the S7-1200's IP address (e.g., 192.168.0.10). Confirm with the S7-1200's display or with TIA Portal's Online & diagnostics > IP address.
  • Remote port: 502 (default for MB_SERVER; can be changed in the instance DB if required by plant network policy).
  • Connect timeout: ≥ 3 seconds. Some clients default to 1000 ms, which is shorter than the S7-1200's first-response window after startup.
  • Unit ID (Slave ID): any value 0..255; the S7-1200 server ignores it for TCP.
  • Polling interval: ≥ 100 ms. Aggressive polling (≤ 20 ms) saturates the CPU's background communication tasks and can mask intermittent STATUS codes.

7. Root Cause: Connection Drops When STATUS Returns to 0000

There are three independent causes that produce this symptom; in field reports, the first is by far the most common.

7.1 MB_SERVER Is Not Called Cyclically

The instruction processes incoming TCP frames only on the PLC scan in which it is called. If the call is in OB1, it runs every cycle. If it is inside a function that is called only on a trigger (for example, "call only when M0.0 = 1"), the instruction misses TCP segments between calls. The client sees a successful first transaction (STATUS cycles 7002 → 0000), the connection then sits idle from the PLC's perspective, and the client's keep-alive timer expires.

Fix: Place the MB_SERVER call unconditionally in OB1 (or in the cyclic OB the project uses as the main scan). Verify by watching MB_SERVER_DB in online mode: NDR and DR should toggle with every request when the client is polling.

7.2 DISCONNECT Input Is Being Driven True

If the DISCONNECT input is wired to a tag that becomes TRUE at any point, the active connection is closed and the server returns to the listening state. STATUS will be 0000 after the close. Check the rung driving DISCONNECT; in many projects it is wired to a startup flag that is never cleared.

Fix: Drive DISCONNECT only on an explicit operator action or fault condition. Use a normally-open contact on a fault tag, not a latched power-on flag.

7.3 Firewall or Anti-Virus Closes the Idle Socket

Windows firewall and most enterprise anti-virus suites treat long-lived, low-traffic TCP sessions as suspicious and close them after a few minutes. The Modbus TCP test client appears to "lose the connection" right after the first successful exchange.

Fix: Add a Windows firewall rule that allows inbound TCP 502 for the test client's executable. Configure the client to send a periodic poll (every 5-10 s) to keep the socket warm. For production gateways, prefer a managed industrial Ethernet switch with QoS rather than a software client.

8. Root Cause: Cannot Write to Registers

If read (FC03/FC04) works but write (FC06/FC16) returns exception 02 (illegal data address) or 04 (slave device failure), inspect the following:

8.1 Holding-Register DB Is Optimized

An optimized data block has no fixed offset. The MB_HOLD_REG pointer relies on a deterministic byte offset, so an optimized DB is invisible to Modbus function codes. Writes return exception 04.

Fix: In the DB properties, uncheck Optimized block access. Recompile and redownload. Verify the DB properties in the project tree; the check box is in the DB's Attributes tab.

8.2 The MB_HOLD_REG Pointer Does Not Match the DB Layout

The pointer is of the form P#<DB number>.DBX<byte offset>.0 WORD <length>. A common mistake is to point at the wrong DB or to declare a length that exceeds the array. The Modbus server then returns exception 02 for any address that falls outside the array.

Fix: Right-click the HoldingReg[0] tag in the DB, choose Copy symbolic information, and paste the absolute address into MB_HOLD_REG. The pointer's length field must match the array size exactly.

8.3 Address Offset in the Client Is Off by One

Modbus addressing is 0-based in the protocol but 1-based in many client tools. If the test client uses "40001" as the first holding register, the request is for address 0x0000; if it uses "40000", the request is for address 0xFFFF (broadcast-equivalent), which the server rejects with exception 02. Always confirm with FC03 first: read one register at the client's "address 0" and verify the value against the PLC's online monitor.

8.4 FC06 / FC16 Use a Different Data Block Than the Pointer Suggests

Some sample programs on the web wire MB_HOLD_REG to a different DB than the one being written. Confirm the pointer in the MB_SERVER_DB instance data block at IDB.HOLD_REG_PTR and trace the symbolic reference back to the source.

9. Verification Procedures

After applying the fixes, run the following verification sequence.

  1. Download the project to the S7-1200 and go to RUN.
  2. Open the MB_SERVER_DB instance data block in TIA Portal online mode and confirm STATUS = 16#0000, CONNECTED = FALSE.
  3. Start the PC test client, configure remote IP = CPU IP, remote port = 502, polling interval = 1 s, function = FC03, address = 0, length = 10.
  4. Confirm the client shows valid words and that MB_SERVER_DB toggles NDR on every poll.
  5. Issue an FC06 write to address 0 with a recognizable pattern (e.g., 0xAAAA) and read back with FC03. Verify the value appears in the online DB monitor.
  6. Issue an FC16 multi-write to addresses 0..3 with a sequence. Verify all four registers in the online DB monitor.
  7. Leave the connection idle for 5 minutes and confirm the client does not report a dropped socket. If it does, see §7.3.
Field tip: For repeatable acceptance testing, capture a Wireshark trace on the test PC. Filter for tcp.port == 502 and confirm the S7-1200 responds with a Modbus/TCP PDU within 50 ms of the client's request. The official Modbus Application Protocol Specification V1.1b3 (available from modbus.org) is the authoritative reference for transaction timing and exception codes.

10. Summary of Settings That Resolve the Source Symptom

Symptom Likely Cause Fix
Connects once, drops when STATUS returns 0000 MB_SERVER not called every cycle Move call to unconditional rung in OB1
Same as above, intermittent DISCONNECT = TRUE at runtime Rewire DISCONNECT to a controlled tag
Drops after 2-3 minutes of idle polling OS firewall / anti-virus Whitelist client on TCP 502; increase poll frequency
Reads work, writes return exception 02 DB is optimized Disable "Optimized block access" on the holding register DB
Reads work, writes return exception 04 MB_HOLD_REG pointer wrong Recreate the pointer from the array's absolute address
Writes to "40001" reach the wrong tag Address offset off by one Verify base address with FC03 read; many tools display 1-based addresses

11. Related Official Documentation

For deeper configuration and the full STATUS-code list for the CPU firmware in use, refer to:

Why does my S7-1200 Modbus TCP server work once and then drop the connection when STATUS returns to 0000?

Almost always because MB_SERVER is not called every PLC scan. Place the call unconditionally in OB1 and verify with the online DB that NDR toggles on every client poll.

Can I read holding registers (FC03) but writes (FC06/FC16) fail on my S7-1200?

Yes, this is typical when the holding-register DB is optimized. Uncheck "Optimized block access" in the DB attributes, recompile, and redownload. Then verify the MB_HOLD_REG pointer matches the DB's absolute byte layout.

Which PC software can I use to test Modbus TCP against an S7-1200 server?

Modbus Poll (commercial), SimplyModbus TCP Client (free with time limit), QModMaster (open source), and Modbus Tools are all reliable. Set the remote IP to the S7-1200's IP, remote port to 502, and Unit ID to 0 or 1.

What does STATUS 16#7002 mean on MB_SERVER?

It means a client request is in process. STATUS 16#0000 means no error and no active job. Both are normal — they are not fault codes. Fault codes begin with 0x8 (e.g., 16#80C8 for timeout, 16#80D2 for server-connection error).

How many Modbus TCP connections can one S7-1200 CPU handle?

Up to eight simultaneous Modbus TCP connections per CPU, shared between MB_CLIENT and MB_SERVER. Configure the count in the CPU properties under Modbus TCP. CPU firmware V4.0 or later is required.

Back to blog