← Mac Change Notes

Why Mac UDP Sockets Show No ESTABLISHED State

A UDP row in Mac lsof output can lack ESTABLISHED even when it carries data. That label describes TCP state. Start by checking the owning PID in Activity Monitor, then inspect its UDP sockets without a TCP state filter.

In this article

Inspect the right process and protocol

In Activity Monitor, find the application or helper you are investigating and note its current process ID, or PID. An app can have several processes, so a familiar name is only a starting point. Apple’s process information guide explains the native inspection view.

In Terminal, replace 12345 with that PID:

/usr/sbin/lsof -nP -a -p 12345 -iUDP

This is a read-only query. It does not send a probe, terminate the process, or alter a firewall setting. The -nP options keep addresses and ports numeric; -p selects the process; -iUDP selects UDP. The important -a combines the selections, so you inspect that PID and its UDP sockets.

Do not copy -sTCP:ESTABLISHED from a TCP-only command into this query. It answers a different question. The official lsof manual documents these filters and warns that protocol-state names differ across operating systems.

No output means no matching socket was visible to this query at that moment. It does not establish that the app never used UDP. The process might have exited, its PID might have changed, or a short-lived socket might already have closed. Visibility can also differ between processes and permissions.

A peer address is not a traffic receipt

UDP sends datagrams without TCP’s connection-establishment handshake. The original protocol specification, RFC 768, does not promise delivery or protection against duplicate messages. An application can build additional behavior on top of UDP; the protocol name alone does not describe that application’s reliability or privacy properties.

A program can still call connect() on a UDP socket. For a datagram socket, Apple’s archived connect(2) manual describes setting the default destination and limiting the peer from which it receives. This is a local socket operation, not TCP’s handshake.

That distinction matters when the NAME column contains an arrow such as 127.0.0.1:51160->127.0.0.1:57653. It can identify the configured peer even before the application sends a datagram. Conversely, a socket without a fixed peer can send to destinations supplied with individual send operations.

The lsof FAQ’s UDP-state explanation also cautions that state reporting depends on the operating-system dialect. Some tools and systems display their own UDP labels. Do not interpret a missing TCP label as evidence that the socket is broken or disconnected from a working service.

What our Mac loopback test showed

On October 9, 2026, we ran a disposable Python test on macOS 15.7.5, Apple Silicon, using the bundled lsof 4.91. All endpoints used 127.0.0.1, so the test stayed inside the Mac. We inspected only the test process, not any installed application’s connections.

We created two UDP sockets, assigned one a default peer, sent a 22-byte test message, and confirmed receipt in the other socket. We also established a separate TCP connection as a comparison.

Test stageWhat lsof showed
Two UDP sockets bound, no sendLocal UDP endpoints, no ESTABLISHED
Default UDP peer assigned, still no sendAn endpoint arrow appeared, still no ESTABLISHED
One 22-byte datagram sent and receivedThe same UDP endpoint display, still no ESTABLISHED
Separate TCP connection establishedIts connected endpoints included ESTABLISHED
UDP descriptors closedThose UDP rows disappeared; TCP rows remained

The key observation is the unchanged UDP display before and after actual receipt. The arrow was already present before sending. The successful transfer came from the test’s receive result, not from an lsof state label or byte counter. We closed all test sockets afterward.

This is evidence for one Mac and tool version, not a guarantee that every lsof build formats UDP identically. It also does not establish whether a particular app is communicating successfully with a remote server, whether that server answered, or what a past exchange contained.

Read the row without overclaiming

Separate four questions when documenting a suspicious-looking result:

  1. Which process owns the descriptor? Record the PID and app version. Recheck the PID after restarting the app.
  2. Which protocol is listed? UDP and TCP need different interpretation. A TCP CLOSE_WAIT state describes a shutdown stage that does not apply to this UDP row.
  3. Which endpoints are visible? Record the local endpoint and any peer, then distinguish a configured destination from confirmed delivery.
  4. What is the real symptom? A failed call, stalled transfer, or missing discovery response is actionable context. An absent word alone is not.

Keep socket rows separate from packet counts. One open socket can carry many messages, and an idle socket can remain visible. The number of rows is not the number of requests. Repeating lsof provides more snapshots, but cannot reconstruct exchanges that happened before you observed them.

Port numbers are clues, too. They do not prove the content or encryption of an exchange; our port 443 guide explains that limit. A wildcard local address also requires a separate reachability analysis, covered in the listener-address guide.

Collect a useful support report

If the app actually fails, record the macOS and app versions, the relevant PID, timestamps, your lsof command, and one small output sample. Describe the action that fails and whether the same action works after a normal app restart. Avoid terminating unfamiliar processes to make a label disappear.

For a broader starting point, use the Mac app network-connections guide. If you need to establish traffic, use an appropriate app log or a scoped diagnostic rather than treating lsof as a packet trace. Redact private addresses and names before sharing evidence publicly.

Keep the conclusion proportional to the observation: the Mac exposed a UDP socket, possibly with a configured peer. Successful delivery requires separate evidence, and missing ESTABLISHED does not decide it.