MQTT TCP Error 80C5 on S7-1200: Root Cause and Fix

David Krause11 min read
S7-1200SiemensTroubleshooting
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

Resolving MQTT TCP Error 80C5 on the SIMATIC S7-1200 (TIA Portal V17)

Field symptom: The PLC establishes ICMP ping to the Mosquitto broker on a Raspberry Pi at 192.168.0.5, but the MQTT Publisher block reports a TCP error code of 80C5 (hex) the moment it is enabled. The instance DB shows the status output of the underlying TCON instruction holding W#16#80C5 while the connection remains in the DISCONNECTED state.

This article documents the exact root cause of 80C5 in the S7-1200 open user communication stack when publishing to a Mosquitto broker, the parameter corrections required inside the LSMqttClient function block shipped in the Siemens Application Example, and the verification steps that confirm a healthy publish cycle. The article is built around the hardware combination reported in the field: a S7-1212 DC/DC/RLY CPU (6ES7212-1AE40-0XB0 or later), firmware 4.4 or newer, programmed with TIA Portal V17, and a Mosquitto broker running on a Raspberry Pi 3/4 on a 192.168.0.0/24 LAN.

1. What Error 80C5 Actually Means

Per the SIMATIC S7-1200 communication manual, the hex code W#16#80C5 is emitted by the TCON instruction when the remote communication partner — in this case the Mosquitto broker on the Raspberry Pi — performed one of the following actions:

  • Refused to establish the TCP connection (the listening socket never accepted the SYN).
  • Terminated an already-established TCP connection (RST received mid-session).
  • Actively ended the connection from the broker side (FIN received while the PLC was idle on a half-open socket).

Source: TCON, TDISCON, TSEND, and TRCV — TCP Communication Instructions.

80C5 is not an MQTT-protocol error. It is a TCP-transport-layer error that the MQTT client surfaces through the TCON status output. Therefore, MQTT-level parameters (Client ID, Topic, QoS, Username/Password) are usually not the trigger. The TCP three-way handshake or the broker's listen() state is.

2. Diagnostic Inputs Required Before Changing Code

Capture the following in the instance DB of the LSMqttClient (or whichever MQTT block you are using from the Siemens Application Example):

Tag Meaning Expected when healthy
status Status word returned by TCON inside the MQTT block W#16#0000 while connected; transient 7000/7001/7002 while establishing
subfunctionStatus Sub-status from TCON / TSEND / TRCV 0000 after successful connect
connectFlag Bit that latches when CONNECT packet is acknowledged TRUE after CONNACK
brokerIP Remote IP of broker 192.168.0.5 in this topology
brokerPort TCP port of broker 1883 (plain) or 8883 (TLS)

Add a temporary String tag, e.g. debugTxt, and concatenate the above into a single human-readable string on every status change. This eliminates guesswork when the PLC is not online with TIA.

3. Root Cause Matrix for 80C5 on S7-1200 → Mosquitto

# Root Cause How to Verify Fix
1 Mosquitto not listening on the IP/port the PLC is targeting (e.g. bound to 127.0.0.1 or ::1 only) From the Raspberry Pi shell: sudo ss -tlnp | grep 1883 Edit /etc/mosquitto/mosquitto.conf: set listener 1883 0.0.0.0 and allow_anonymous true (or configure ACLs)
2 Firewall on Raspberry Pi (iptables / nftables / ufw) blocking inbound TCP 1883 sudo ufw status, sudo iptables -L -n -v sudo ufw allow 1883/tcp or remove the rule blocking the PLC's subnet
3 PLC TSAP, remote IP, or port configured incorrectly in the TCON connection DB (TCON_Param) Inspect the connection DB used by the MQTT block; verify RemoteAddress = 192.168.0.5, RemotePort = 1883 Re-enter the connection parameters and re-download the project
4 PLC subnet mask / gateway mismatch — ICMP works because it is ARP-driven, but routed TCP fails From TIA: Online & Diagnostics > PROFINET interface > IP suite Set 192.168.0.x / 255.255.255.0 on the PLC to match the LAN
5 Client ID collision — another MQTT client is already using the same Client ID and Mosquitto is configured to reject it Tail /var/log/mosquitto/mosquitto.log on the Pi Change the Client ID in the MQTT block to a unique value
6 Mosquitto max_connections or max_queued_messages reached; broker closes new connections immediately mosquitto_pub -h 127.0.0.1 -t test -m hello from the Pi Increase max_connections or restart the broker
7 Keepalive timeout (default 60 s) on a PLC program that never calls the MQTT block in OB1 — broker drops idle sockets Check if 80C5 appears exactly after 60 s of no cyclic trigger Call the MQTT block every cycle in OB1, or send a periodic keepalive ping
8 Use of TLS (8883) without the S7-1200 supporting Sec TLS configuration; PLC terminates handshake with RST Compare configured brokerPort to actual broker listener Use plain TCP 1883 unless the CPU is a 1215/1217 with security-capable firmware and proper cert import

In the field case reported, ping succeeds, which eliminates cause #4. The most common cause with a default Mosquitto install on Raspberry Pi OS is cause #1: Mosquitto binds only to the loopback interface because /etc/mosquitto/mosquitto.conf contains bind_address 127.0.0.1 or no listener at all, so the broker silently rejects every external TCP SYN with an RST, and the PLC's TCON reports 80C5.

4. Step-by-Step Resolution

4.1 Prerequisites

  • PC with TIA Portal V17 (or V16/V18 with the matching Application Example version) installed and an active project for the S7-1212.
  • Raspberry Pi running Raspberry Pi OS with mosquitto and mosquitto-clients installed: sudo apt-get install mosquitto mosquitto-clients.
  • SSH access to the Pi (default user pi).
  • Ethernet cabling on a common 192.168.0.0/24 subnet. PLC IP example: 192.168.0.10, broker IP: 192.168.0.5.
  • The Siemens Application Example "SIMATIC S7-1200 / S7-1500 with MQTT" imported (Home > Application Examples in TIA Portal).

4.2 Configure Mosquitto to accept external connections

  1. On the Raspberry Pi, edit the broker config:
    sudo nano /etc/mosquitto/mosquitto.conf
  2. Append the minimum stanza required for a permissive lab/test setup:
    listener 1883 0.0.0.0
    allow_anonymous true
    max_connections 100
    max_queued_messages 1000
  3. Restart and confirm:
    sudo systemctl restart mosquitto
    sudo ss -tlnp | grep 1883
    # Expected: LISTEN 0 100 0.0.0.0:1883 ... users:(("mosquitto",pid=...))
  4. From the PLC engineering PC, prove external reachability with the Mosquitto client utility before touching the PLC code:
    mosquitto_pub -h 192.168.0.5 -t test -m hello
    If this returns no error, the broker is reachable on TCP 1883 from the LAN.

4.3 Configure the TCON connection on the S7-1200

  1. In TIA Portal, open the connection DB generated by the MQTT Application Example (typically named "MQTT_Connection_DB" or as defined in the block's TCON_Param UDT).
  2. Set the following TCON_Param fields exactly:
    InterfaceId    := 64   (PROFINET interface of the S7-1200)
    ID             := 1    (must match the ID used in the TCON call)
    ConnectionType := 16#0B (TCP/IP, native)
    ActiveEstablishment := TRUE  (PLC is the active connection partner)
    RemoteAddress  := 192.168.0.5
    RemotePort     := 1883
    LocalPort      := 0     (let the CPU assign an ephemeral port)
    LocalTsapId    := 16#0000
    RemoteTsapId   := 16#0000
  3. Compile the project (Project > Compile > Software rebuild) and download to the CPU.

4.4 Configure the MQTT Publisher block

  1. Open the LSMqttClient instance DB.
  2. Set the static parameters:
    • brokerIP = '192.168.0.5' (STRING, 15 chars)
    • brokerPort = 1883
    • clientId = unique string, e.g. 'S71200_1212_01'
    • keepAlive = 60 (seconds; match this in connectFlag settings if the example exposes it)
    • cleanSession = TRUE as the start value and as a hard-coded value at the connectFlag input — do not leave it as a parameter that the HMI can write to FALSE by accident
    • username / password = leave blank for anonymous; otherwise configure matching credentials in mosquitto.conf with password_file
  3. Wire the enablePublish input to a TRUE constant first to isolate the issue, then refine to a conditional trigger.
  4. Call the LSMqttClient block in OB1 on every cycle, not in a slow OB. The MQTT Application Example is state-machine-driven and expects cycle-time calls to advance the connect/subscribe/publish phases.

4.5 Verification

  1. Go online with TIA Portal. Monitor the MQTT block instance DB.
  2. Confirm:
    • status = W#16#0000
    • connectFlag = TRUE
    • subfunctionStatus = 0000
  3. On the Raspberry Pi, subscribe to the test topic:
    mosquitto_sub -h 127.0.0.1 -t siemens/plc/data -v
  4. Toggle the publish input on the MQTT block. Each toggle should produce a line such as:
    siemens/plc/data {"value":42}
  5. If 80C5 still occurs after the broker is verified externally reachable, capture wireshark on the Pi with tcp.port == 1883 and confirm whether the broker returns a RST or never responds to the SYN.

5. Quick Diagnosis Procedure (Field Flowchart)

PLC reports TCON status W#16#80C5 Ping PLC <-> Pi succeeds? ss -tlnp | grep 1883 on Pi shows 0.0.0.0:1883 ? Check TCON_Param: RemoteAddr/Port/ID Add listener 1883 0.0.0.0 allow_anonymous true Fix ID, IP, Port; re-download HW config

6. Firmware and Library Compatibility Notes

The MQTT Application Example uses the TCON, TSEND, and TRCV instructions from the SIMATIC basic instructions library, which are present on every S7-1200 CPU firmware ≥ 4.2. For an S7-1212 DC/DC/RLY the relevant catalog numbers and minimum firmware are:

CPU MLFB Min FW for MQTT example TIA Portal
S7-1212 DC/DC/RLY 6ES7212-1AE40-0XB0 V4.4 V15.1 / V16 / V17
S7-1212 DC/DC/RLY (newer) 6ES7212-1BE40-0XB0 V4.5 V17 / V18

If the firmware is older than V4.2, TCON exists but TLS-secured variants are not available. Do not attempt TLS/8883 unless the CPU firmware explicitly supports the Sec connection type and you have imported the broker certificate into the PLC certificate store.

7. OB1 Wiring and Cycle-Time Considerations

The MQTT client is implemented as a state machine. It must be called every PLC cycle to:

  • Drive TCON retries if the broker is briefly unreachable.
  • Forward TSEND/TRCV completion events for in-flight MQTT fragments.
  • Refresh the keep-alive timer.

Recommended OB1 call pattern:

// OB1 - always called every scan
// Trigger publisher on a rising edge of a tag
IF publishCmd AND NOT publishCmdOld THEN
    publishTrigger := TRUE;
END_IF;
publishCmdOld := publishCmd;

// Run the MQTT state machine unconditionally
LSMqttClient_DB(
    enable        := TRUE,
    publish       := publishTrigger,
    payload       := payloadString,
    topic         := topicString,
    brokerIP      := '192.168.0.5',
    brokerPort    := 1883,
    clientId      := 'S71200_1212_01',
    keepAlive     := 60,
    cleanSession  := TRUE,
    status        => mqttStatus,
    subStatus     => mqttSubStatus,
    connected     => mqttConnected
);

IF publishTrigger THEN
    publishTrigger := FALSE; // single-shot
END_IF;

Calling the block only on a slow event OB or a one-shot will cause the broker to drop the keep-alive and the next reconnect attempt will return 80C5 as the broker terminates the half-open socket.

8. Mosquitto-Side Hardening (After the Error Is Gone)

Once 80C5 no longer appears, lock the broker down for production use:

# /etc/mosquitto/mosquitto.conf
listener 1883 0.0.0.0
allow_anonymous false
password_file /etc/mosquitto/passwd
acl_file /etc/mosquitto/acl
max_connections 10
max_queued_messages 100
log_type error
log_type warning
log_type notice
log_dest file /var/log/mosquitto/mosquitto.log

Create credentials and reload:

sudo mosquitto_passwd -c /etc/mosquitto/passwd plc
sudo systemctl restart mosquitto

Then set username = 'plc' and password = the configured password in the LSMqttClient block.

9. Alternative Architectures

If 80C5 persists despite a verified reachable broker, the S7-1200 can publish through an intermediate broker protocol gateway:

  • Node-RED on the Raspberry Pi: install Node-RED with node-red-contrib-s7 and node-red-contrib-mqtt-broker. The PLC uses ISO-on-TCP (ConnectionType = 16#12) to Node-RED, which in turn publishes to Mosquitto. 80C5 is then a pure PLC-Node-RED issue and easier to diagnose with Node-RED's debug pane.
  • Siemens IOT2050 / SIMATIC IOT1050: industrial-grade gateway that natively runs an MQTT broker and avoids consumer-grade Raspberry Pi networking quirks.
  • Cloud MQTT: AWS IoT Core, Azure IoT Hub, or HiveMQ Cloud. Use TLS 8883 with the S7-1500 (which has full Sec support) rather than the S7-1200 if TLS is required.

10. Quick-Reference Error Code Table for S7-1200 Open User Communication

Hex Code Meaning (TCON family) Likely Cause
7000 Connection not yet established, no call active Initial state
7001 Connection establishment started TCON in progress
7002 Connection establishment finished, waiting for partner Waiting for remote ACK
80C0 Local resource in use (duplicate ID) Same ID used by two TCONs
80C1 Local resource error (out of connections) CPU connection limit reached
80C3 Remote partner not reachable (timeout) Wrong IP, ACL, routing
80C5 Connection refused / terminated by remote partner Broker not listening, RST, or keepalive timeout
80C7 TCP reset by remote during data transfer Broker crashed mid-publish

Source for codes: SIMATIC S7-1200 Manual Collection — TCON / TSEND / TRCV.

11. Verification Checklist

Use this list before declaring the fault cleared:

  • ss -tlnp | grep 1883 on the Pi shows 0.0.0.0:1883, not 127.0.0.1:1883.
  • mosquitto_pub from a third host (or the Pi itself) on the LAN returns success.
  • TCON status = W#16#0000 in the instance DB after the publisher is enabled.
  • connectFlag = TRUE.
  • mosquitto_sub on the Pi receives published payloads within one cycle of the trigger.
  • After 5 minutes of idle, no 80C5 reappears — confirming keep-alive is being honored.
  • /var/log/mosquitto/mosquitto.log shows New connection from 192.168.0.10 (the PLC's IP) and Client S71200_1212_01 connected.

12. Frequently Asked Questions

Is 80C5 an MQTT error or a TCP error?

It is a TCP-transport-layer error raised by the TCON instruction: the remote partner (Mosquitto) refused the connection, terminated it, or actively ended it. It is surfaced through the MQTT client block but originates in TCP. Reference: TCON manual.

Ping works but MQTT fails with 80C5 — why?

ICMP uses ARP and does not validate that a TCP port is open. Mosquitto by default may bind only to 127.0.0.1, so the PLC's SYN is met with a RST and TCON reports 80C5. Add listener 1883 0.0.0.0 in /etc/mosquitto/mosquitto.conf.

Which TIA Portal version is required for the S7-1200 MQTT example?

The Siemens MQTT Application Example is compatible with TIA Portal V15.1 and newer, including V16, V17, and V18. TIA V17 is sufficient for an S7-1212 with firmware 4.4 or higher.

Should cleanSession be TRUE or FALSE on the S7-1200?

For most PLC telemetry use cases, set cleanSession = TRUE as a hard-coded start value at the connectFlag input. This prevents stale session state from causing the broker to drop a reconnect with a TCP reset.

Can the S7-1200 use TLS (port 8883) with Mosquitto?

Only S7-1200 CPUs with security-capable firmware and properly imported certificates can use ConnectionType = 16#0D with TLS. For an S7-1212 used in lab/pilot, use plain TCP 1883 and isolate the broker on a private VLAN. Move to TLS only when migrating to an S7-1500 or a security-enabled 1215/1217 with full certificate management.

Back to blog