In this lesson

What this lesson covers

  • A capture that holds only Modbus traffic, and where to measure it
  • Pairing a request with its response through the transaction id
  • One filter for every exception, and Decode As on another port

Read first: Port 502, the MBAP header and the unit id, Practise Modbus TCP with a free simulator

Wireshark shows you the bytes that actually crossed the network, which is the fastest way to settle whether a Modbus TCP problem is yours, the device's or the gateway's. A capture turns "it does not work" into a frame you can read field by field. After this lesson you can record only Modbus traffic, pair request with response through the transaction id, pull out every exception with one filter, and attach the dissector to a port other than 502.

Capturing only Modbus traffic

Set a capture filter before you press start, not afterwards.

tcp port 502

Against the simulator from the lesson on practising with a simulator that becomes tcp port 5020. The filter discards packets at the moment of capture, so on a busy site you keep a few hundred frames instead of a few hundred thousand.

Where you measure decides what you see at all. Run Wireshark on the polling machine itself. A random switch port gives you nothing, because a switch forwards traffic only to the ports involved, so watching two other devices talk needs a mirror port or a tap.

A capture separates three fault pictures that look identical from the client side.

What you seeWhat it meansWhere you lookNo response at allYour request went out onthe wire and nothing cameback inside the timeoutUnit id the devicesilently ignoresProtocol id not 0x0000,discarded without a...Connection limit, orgateway waiting on...An exception, forexample 83 0BSomething answered you. Itis refusing this onerequestException 02: PDUaddress against...Exception 0B: thedevice behind the...Exception 06: you arepolling too hardData, but the wrongvalueThe transport is fine, theinterpretation is notData type and wordorderScaling factor and unitWrong register from thedatasheet
Three fault pictures a capture separates in seconds. Decide which column you are in before you change a single setting.

What the packet pane actually shows

Wireshark splits a Modbus frame into two layers you can open separately: the MBAP header and the PDU underneath. Here is a read of three holding registers, twelve bytes on the wire: 00 01 00 00 00 06 FF 03 00 6B 00 03.

BytesFieldWhat it says
00 01Transaction identifier1, the client picks it
00 00Protocol identifier0, always
00 06Length6 bytes follow: 1 unit id plus 5 PDU
FFUnit identifier255, device is on the network itself
03Function codeFC03, read holding registers
00 6BStart addressPDU address 107, datasheet number 40108
00 03QuantityThree registers

The answer is fifteen bytes: 00 01 00 00 00 09 FF 03 06 02 2B 00 00 00 64. Six of the seven header bytes come straight back unchanged. Only Length goes from 6 to 9: the server alone knows how much it is about to send, 1 unit id plus 8 PDU bytes.

MBAP header, 7 bytesPDU, identical to the RTU oneTID2 BPID2 BLEN2 BUID1 BFC1 BDATAN BCRC-16
TIDTransaction id, pairs answer with request
PIDProtocol id, always 0
LENLength, number of bytes after this field
UIDUnit id, the address behind a gateway
FCFunction code
DATAData

No CRC: Ethernet and TCP already check integrity

What Wireshark shows as two layers: seven header bytes, then the same PDU that travels over RS485.

The rule this whole lesson leans on: Length counts the unit id plus the PDU, so the complete frame is always Length plus six.

Three filters you always use

Capture filters and display filters are different languages; the one you type in the bar during analysis is the display filter. Three of them cover most of the work.

FilterWhat you get
mbtcpEvery Modbus TCP frame in the capture
modbus.func_code == 3Only the reads with FC03
modbus.exception_codeOnly the frames carrying an exception

The third one is worth memorising. It holds no comparison at all: naming a field on its own matches every packet that has it, so it becomes your "what is going wrong here" filter. Which devices speak Modbus in the first place is a different question, and a Modbus network scan answers that faster than any capture.

Tying request and response together

mbtcp.trans_id == 5 puts one transaction on screen, question and answer together, and that is how you tell a missing reply from a slow one.

The server copies the transaction id out of the request into the response unchanged, so the pairing stays exact even with several requests in flight on one connection. Filter on the number and count what you get: two frames means the transaction completed, one frame means nothing answered. The time column tells you how long the device took, which settles whether your timeout is too short. The field itself is covered in the lesson on the MBAP header and the unit id.

Attaching the dissector to another port

The Modbus dissector is bound to port 502, so on any other port Wireshark shows plain TCP with an uninterpreted data blob, and mbtcp matches nothing. Right click a packet, choose Decode As, set the TCP port to Modbus/TCP, and the same packets are dissected from then on.

You need this more often than you would expect. The pymodbus simulator listens on 5020 because a port below 1024 needs administrator rights, and SolarEdge inverters commissioned with SetApp default to 1502. The specification says port 502 must stay available even when a second port is configured, and not every manufacturer honours that.

What a capture tells you about the gateway

Two exception codes only ever come from a gateway, and both are good news: they prove your network side works. Here is that same read refused, assembled from the rules in the specification: 00 01 00 00 00 03 01 83 0B.

BytesFieldMeaning
00 01Transaction idCopied from the request
00 00Protocol id0
00 03Length3, so 1 unit id plus 2 PDU bytes
01Unit idThe server address on the RS485 side
83Function code0x03 plus 0x80, so an exception
0BException codeGateway target device failed to respond

That reply came back fast, and from the gateway rather than the meter. The gateway put your request on the RS485 bus and nothing answered on address 1, so you check the server address, the baud rate, the parity and the wiring instead of the firewall. Exception 0A, gateway path unavailable, points at the gateway itself: misconfigured or overloaded. Configuring both sides is in the Modbus TCP gateway setup guide.

If nothing comes back at all, you still saw your request leave: the gateway is waiting out its own serial timeout, or the device has run out of connections. SolarEdge, for one, supports a single connection.

When Wireshark will not help you

On RS485 there is nothing for Wireshark to listen to: it captures from network interfaces, and a differential pair is not one. You can bridge a serial port in with extra tooling, but in daily work you use your client's poll statistics and the FC08 diagnostic counters, the way the RTU troubleshooting lesson does.

The second limit is meaning. A capture proves that datasheet number 40108 returned 02 2B, which is 555 decimal. Whether that is 55.5 amps, 555 watts or a status code is a datasheet question. It is also this readable because plain Modbus TCP has no authentication and no encryption, which is why Modbus TCP explained treats segmentation as part of the design.

There is a practical limit as well: on a managed workstation you cannot always install Wireshark, or you are not allowed to. The Protocol Analyzer in ModbusCloud Diagnostics then shows the frames of its own connection, colour coded per field and with a counter for transactions and errors. Watching the traffic of another client still needs Wireshark and a mirror port.

Common mistakes

  1. Starting without a capture filter. On a live network you collect hundreds of thousands of packets in minutes, the ring buffer wraps, and the frames you needed are gone. Type tcp port 502 before you press start.

  2. Concluding that Wireshark cannot see the simulator. On port 5020 the dissector is not attached, so you see plain TCP and assume nothing is being captured. Clear the display filter first: if TCP packets are there, the problem is interpretation and Decode As fixes it.

  3. Measuring on an ordinary switch port. You plug your laptop into a free port, capture nothing, and conclude the device is dead. Capture on the polling machine itself, or set up a mirror port.

  4. Taking a missing response for a network problem. You see the request leave and nothing come back, and you go open firewall rules. Check the connection limit and the gateway first: a gateway waiting out a serial timeout produces silence, and so does a unit id the device ignores.

Get hands-on

You capture two transactions yourself, one that succeeds and one that fails, and find each back with its own filter.

  1. 1

    Start the simulator and the capture

    Run the pymodbus simulator on port 5020, then start Wireshark on the loopback interface with capture filter tcp port 5020. Both are free to use, including commercially.

  2. 2

    Read one register

    Fire off a read with your client. If you see only plain TCP, right click a packet, choose Decode As, and map TCP port 5020 to Modbus/TCP.

  3. 3

    Name the seven MBAP bytes

    Open the request and walk through transaction id, protocol id, Length and unit id. Note the transaction id, and check that Length equals 1 plus the number of PDU bytes.

  4. 4

    Put the transaction back together

    Set the display filter to mbtcp.trans_id == followed by your number. Two frames means the transaction completed.

  5. 5

    Provoke an exception

    Read a PDU address far past the end of the map, then filter on modbus.exception_code and you are left with that one frame.

  6. 6

    Compare the two answers

    The exception has Length 0x0003 and a function code above 0x80, the successful read has a byte count and register data behind it. Finish the byte table for the exception frame yourself, the way it is laid out earlier in this lesson.

The read in step two from the command line, one holding register at PDU address 3 on unit id 1:

mbpoll -m tcp -p 5020 -a 1 -t 4 -r 3 -c 1 -0 -1 127.0.0.1

With real equipment. Swap port 5020 for 502 and capture on the polling machine or a mirror port. Behind a gateway, put the RS485 server address in the unit id, then try a wrong one on purpose: exception 0B is what you are after.

Expected result: one capture holding a successful transaction and an exception, each found again with its own filter.

Summary

  • A capture filter such as tcp port 502 decides what you keep at the moment of capture, which is the difference between a few hundred frames and a few hundred thousand.
  • The transaction id pairs question with answer, so mbtcp.trans_id shows at a glance whether a response was missing or merely late.
  • The filter modbus.exception_code names a field without a comparison, which is why it pulls every failed request out at once.
  • On a port other than 502 the dissector is not attached, so Decode As is routine and not a workaround.
  • Exception 0B comes from the gateway and proves your network side works, so the search moves to the RS485 bus.

Check yourself

Four questions about this lesson. Every answer comes with an explanation.

Question 1 of 4
Your capture shows one request per second, and every single one is answered with modbus.exception_code == 11. Where do you go looking?
You start Wireshark on the loopback interface with display filter mbtcp while the simulator runs on port 5020, and the list stays empty. Why?
A response in your capture has Length 0x0003. What do you already know before you open the PDU?
Why does Wireshark not help you with an RS485 problem?

Stuck on a project?

Describe what you see and where it goes wrong. We will look at it and tell you what we would do.

Further reading in the knowledge base