Skip to main content

Troubleshooting · Ports · Cross-platform

How to find what is using a port on Windows, Linux, and macOS

Identify the process behind “address already in use” with PowerShell, ss, lsof, or one read-only QZX command that returns structured evidence across supported platforms.

By Alejandro Sánchez, creator of QZX9 min read
Open inspectPort

A port conflict often appears when a development server, database, local API, container, or helper process is already listening where a second program wants to bind. The useful first question is not “what should I kill?” It is “what owns this port right now?”

That distinction matters because the owner may be exactly the service you intended to keep running. A diagnostic should identify evidence first and leave process mutation as a separate decision.

Windows: find the owner with PowerShell

Windows exposes the local port and owning process through Get-NetTCPConnection. For a TCP listener on port 3000:

Get-NetTCPConnection -LocalPort 3000 -State Listen |
  Select-Object LocalAddress, LocalPort, State, OwningProcess

Then inspect the returned PID without terminating it:

Get-Process -Id <PID>

For UDP, Windows exposes bound endpoints separately through Get-NetUDPEndpoint. TCP and UDP are different protocols, so a robust diagnostic should not silently treat one as the other.

Linux: inspect listeners with ss

On Linux, ss can show listening sockets, numeric ports, and process information. A focused TCP check can be:

ss -lptn 'sport = :3000'

The -l option limits output to listeners, -p asks for process information, -t selects TCP, and -n keeps ports numeric. Process details can depend on permissions, so missing process metadata is not proof that no owner exists.

macOS: use lsof for the listening process

A common macOS check for a TCP listener is:

lsof -nP -iTCP:3000 -sTCP:LISTEN

For a UDP endpoint, use a UDP-specific query rather than assuming the TCP listener command covers it:

lsof -nP -iUDP:3000

One QZX command across supported platforms

QZX exposes inspectPort as a read-only diagnostic:

qzx inspectPort 3000 --json

The command reports whether the port is in use and, when the operating system exposes the evidence, returns observed PIDs and process details such as name, creation time, executable, command line, username, and memory information. It also reports limitations and non-fatal detail errors instead of inventing unavailable data.

qzx inspectPort 5173 --json
qzx inspectPort 5432 --json
qzx inspectPort 8000 --json

Those are examples, not assumptions about which application owns a given port on your machine.

How to read the result safely

  • status says whether the inspection resolved to free or in_use.
  • observed_pids contains process IDs observed as owners when available.
  • processes contains process evidence that the host allowed QZX to read.
  • limitations tells you what could not be resolved on that host.
  • errors preserves non-fatal detail failures without discarding an otherwise useful diagnosis.

A successful inspection means QZX completed the diagnostic. It does not mean the owner is safe to terminate or unnecessary.

Read-only does not mean safe to publish verbatim

Process metadata can contain more context than you expect. Command-line arguments may include local paths, usernames, URLs, project names, tokens, credentials, or customer identifiers. Before pasting raw output into a public issue, forum, ticket, chat, or AI conversation, remove fields that are not necessary for the diagnosis.

This is an important boundary: the command does not mutate the process, but its output can still be sensitive.

A safer port-conflict sequence

  1. Inspect. Run the diagnostic for the exact port.
  2. Confirm. Check whether the port is actually occupied and whether an owner is visible.
  3. Understand. Review the process name, PID, executable, creation time, and limitations.
  4. Decide separately. Determine whether the owner is expected before changing process state.
  5. Re-inspect immediately before a mutation. PIDs can be reused after a process exits.
  6. Verify afterward. Inspect the port again instead of assuming it became free.

inspectPort deliberately stops at diagnosis. Separating evidence from mutation makes the workflow more useful to both human operators and AI agents.

A compact prompt for an AI agent

After reviewing the JSON for sensitive fields, you can give an agent a narrow instruction:

I ran qzx inspectPort 3000 --json.
Review the PID, process name, creation time, executable,
limitations, and errors I provide. Explain the likely owner
without assuming it should be killed. Propose one read-only
next check first. Treat missing fields as unknown.

This keeps the model anchored to observed evidence instead of turning a simple binding conflict into speculative process management.

Frequently asked questions

How do I find what process is using port 3000?

Use the platform-native listener tools or run qzx inspectPort 3000 --json for the QZX structured diagnostic. Review the owner before deciding whether any process should be stopped.

Does inspectPort kill the process?

No. inspectPort is read-only. It identifies occupancy and process evidence but does not terminate or modify the listener.

Why can process details be missing?

Operating-system APIs, permissions, race conditions, or a process exiting during inspection can limit what can be read. QZX reports those limitations rather than treating missing metadata as certainty.

Can I paste the JSON into a public issue?

Review it first. Process command lines, executable paths, usernames, and arguments can reveal sensitive information even though the inspection itself is read-only.

Primary sources and further reading