Resolving MQTT TCP Error 80C5 on the SIMATIC S7-1200 (TIA Portal V17)
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
mosquittoandmosquitto-clientsinstalled: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
- On the Raspberry Pi, edit the broker config:
sudo nano /etc/mosquitto/mosquitto.conf - 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 - Restart and confirm:
sudo systemctl restart mosquitto sudo ss -tlnp | grep 1883 # Expected: LISTEN 0 100 0.0.0.0:1883 ... users:(("mosquitto",pid=...)) - From the PLC engineering PC, prove external reachability with the Mosquitto client utility before touching the PLC code:
If this returns no error, the broker is reachable on TCP 1883 from the LAN.mosquitto_pub -h 192.168.0.5 -t test -m hello
4.3 Configure the TCON connection on the S7-1200
- In TIA Portal, open the connection DB generated by the MQTT Application Example (typically named
"MQTT_Connection_DB"or as defined in the block'sTCON_ParamUDT). - Set the following
TCON_Paramfields 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 - Compile the project (Project > Compile > Software rebuild) and download to the CPU.
4.4 Configure the MQTT Publisher block
- Open the
LSMqttClientinstance DB. - 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 inconnectFlagsettings if the example exposes it) -
cleanSession=TRUEas the start value and as a hard-coded value at theconnectFlaginput — do not leave it as a parameter that the HMI can write toFALSEby accident -
username/password= leave blank for anonymous; otherwise configure matching credentials inmosquitto.confwithpassword_file
-
- Wire the
enablePublishinput to a TRUE constant first to isolate the issue, then refine to a conditional trigger. - Call the
LSMqttClientblock 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
- Go online with TIA Portal. Monitor the MQTT block instance DB.
- Confirm:
-
status=W#16#0000 -
connectFlag=TRUE -
subfunctionStatus=0000
-
- On the Raspberry Pi, subscribe to the test topic:
mosquitto_sub -h 127.0.0.1 -t siemens/plc/data -v - Toggle the
publishinput on the MQTT block. Each toggle should produce a line such as:siemens/plc/data {"value":42} - If
80C5still occurs after the broker is verified externally reachable, capturewiresharkon the Pi withtcp.port == 1883and confirm whether the broker returns a RST or never responds to the SYN.
5. Quick Diagnosis Procedure (Field Flowchart)
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
TCONretries if the broker is briefly unreachable. - Forward
TSEND/TRCVcompletion 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-s7andnode-red-contrib-mqtt-broker. The PLC uses ISO-on-TCP (ConnectionType = 16#12) to Node-RED, which in turn publishes to Mosquitto.80C5is 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
Secsupport) 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 1883on the Pi shows0.0.0.0:1883, not127.0.0.1:1883. -
mosquitto_pubfrom a third host (or the Pi itself) on the LAN returns success. - TCON
status=W#16#0000in the instance DB after the publisher is enabled. -
connectFlag=TRUE. -
mosquitto_subon the Pi receives published payloads within one cycle of the trigger. - After 5 minutes of idle, no
80C5reappears — confirming keep-alive is being honored. -
/var/log/mosquitto/mosquitto.logshowsNew connection from 192.168.0.10(the PLC's IP) andClient 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.