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:
- The PC client (e.g., SimplyModbus, Modbus Poll) successfully opens a TCP session on port 502 of the S7-1200.
- On the PLC side, the
MB_SERVERinstance DB showsSTATUS = 16#7002(job processing) and the client can perform one or more transactions. - Once
STATUSreturns to16#0000, the client loses the connection, and reconnect attempts fail until the PLC program is re-downloaded. - 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.
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
- In the project tree, select Add new block > Data block (DB).
- Uncheck Optimized block access. Optimized DBs cannot be addressed by Modbus function codes because the byte offset is not deterministic.
- 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
- Note the absolute byte offset of
HoldingReg[0]. In a non-optimized DB, the offset is the sum of preceding static data; here,HoldingRegstarts at offset 0.
4.2 Insert and Wire MB_SERVER
- Open the main OB (typically OB1) and drag
MB_SERVERfrom the task card into a network. - Create an instance DB when prompted (e.g.,
MB_SERVER_DB). - 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). |
- Ensure
MB_SERVERis 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.
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.
- Download the project to the S7-1200 and go to RUN.
- Open the
MB_SERVER_DBinstance data block in TIA Portal online mode and confirmSTATUS = 16#0000,CONNECTED = FALSE. - Start the PC test client, configure remote IP = CPU IP, remote port = 502, polling interval = 1 s, function = FC03, address = 0, length = 10.
- Confirm the client shows valid words and that
MB_SERVER_DBtogglesNDRon every poll. - 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.
- Issue an FC16 multi-write to addresses 0..3 with a sequence. Verify all four registers in the online DB monitor.
- Leave the connection idle for 5 minutes and confirm the client does not report a dropped socket. If it does, see §7.3.
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:
- MB_CLIENT / MB_SERVER instruction reference in the SIMATIC S7-1200 Manual Collection (TIA Portal documentation portal)
- SIMATIC S7-1200 Programmable Controller System Manual, chapter on "Modbus TCP communication" — accessible from the same TIA Portal documentation portal under the S7-1200 system manual entry.
- Modbus Application Protocol Specification V1.1b3 — published by the Modbus Organization (modbus.org), the authoritative reference for function codes and exception codes.
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.