Netcat Command in Linux: Commands That Work on Your System

LinuxForDevices featured banner: Run The Right Netcat

nc is three programs sharing one name, and the option table you find usually belongs to the wrong one.

On Ubuntu and Debian the nc in your PATH is netcat-openbsd, which dropped the flags that netcat-traditional and Nmap’s ncat kept, so a line copied from a guide about either of those fails the moment you run it. I ran every command below against the nc that ships with Ubuntu 24.04, including the ones that error out, so you can see the output before you paste anything into a shell.

Which netcat you actually have

Netcat began as one program in 1996 and now survives as three separate codebases that share the name. Each accepts a different set of flags, so the first job is finding out which binary your nc resolves to.

nc -h 2>&1 | head -2; dpkg-query -W -f='${Package} ${Version}\n' netcat-openbsd

That first line is the tell. A netcat-openbsd build prints OpenBSD netcat with a Debian patchlevel, netcat-traditional prints its own version banner, and ncat prints a usage block that names Nmap.

Terminal showing nc -h reporting OpenBSD netcat 1.226-1ubuntu2 and the installed netcat-openbsd package version
The first line identifies the implementation, and the package query confirms which build is installed.

Install by package name rather than by the netcat metapackage, because that metapackage resolves to whichever variant your distribution prefers.

sudo apt install netcat-openbsd    # Debian and Ubuntu
sudo dnf install nmap-ncat         # Fedora and RHEL
sudo pacman -S openbsd-netcat      # Arch
VariantPackage nameShips as nc onFlags the others lack
netcat-openbsdnetcat-openbsdDebian, Ubuntu, Alpine-q, -N, -I, -O
netcat-traditionalnetcat-traditionalolder Debian, EPEL-e, -c, -o, -G
ncatnmap-ncatFedora, RHEL, CentOS, Windows–ssl, –sh-exec, –proxy, –allow

Connect mode and listen mode

Every nc command is one of two shapes, either a connect to a host and port or a listen on a port that waits for someone to arrive.

nc [options] host port      # connect mode
nc -l port                  # listen mode

A hostname that will not resolve fails before netcat opens anything, so check name resolution first when a connect dies immediately. The exact error text differs by variant, and Ubuntu prints a name or service not known message that points at how your interface address and DNS resolver are configured rather than at the port.

Running both ends on one machine is the fastest way to watch the pair work, with the listener waiting on port 9002 and writing whatever arrives into a file while the client sends a single line.

nc -l 9002 > /tmp/nc-recv.txt & sleep 0.5; printf 'ping from the client\n' | nc -q 1 127.0.0.1 9002; wait; cat /tmp/nc-recv.txt
Terminal showing a netcat listener receiving the line ping from the client on port 9002
The client sends one line with -q 1, and the listener writes it to the file named after the redirect.

Without -q 1 the client keeps the connection open after its input ends, so the command appears to hang even though the listener already received the line.

OpenBSD nc accepts the listen port positionally or through -p, so nc -l 3000 and nc -l -p 3000 reach the same place. In connect mode -p means something else entirely, and it sets the local source port rather than a destination.

Two-way chat between two terminals

A netcat connection is a stream in both directions, so two terminals on the same machine turn it into a chat channel where neither end formats anything.

Terminal showing a netcat listener on port 8080 receiving lines typed from a second terminal
The listening terminal shows every line the other side types.
Terminal showing a netcat client connected to 127.0.0.1 on port 8080 exchanging typed lines
The connecting terminal writes into the same stream, so both ends can type.

The listener accepts a single connection and prints every line the other side types, and the client writes into the same stream. Closing either end ends the conversation.

Check whether a port is open

Scanning uses zero-I/O mode, which opens a connection and closes it without sending a byte. Add verbose mode to see the failures as well as the successes.

nc -zv 127.0.0.1 9003 2>&1; echo "exit status: $?"; nc -l 9004 & sleep 0.5; nc -zv 127.0.0.1 9004 2>&1; echo "exit status: $?"
Terminal showing nc -zv against a refused port returning exit status 1 and against an open port returning exit status 0
Both scans print a line, and the exit status is what separates them in a script.

The exit status is what a script can act on. A refused port returns 1 and an open port returns 0, so you can test a service without parsing any text.

What you wantCommandWhat comes back
one portnc -zv host portsucceeded line and exit 0, or refused and exit 1
a rangenc -zv host 8000-8010one line per port, successes and refusals alike
several portsnc -z host 22 80 443only the ports that answered
several ports, quietnc -z host 22 80 443nothing at all when every port is closed

A range scan is the same command with the ports joined by a hyphen, so every port in the range gets its own line. The refused entries are what tell you the range actually ran.

Terminal showing a netcat scan of ports 20 to 25 where only port 22 accepted the connection
A range scan reports every port it tried, so the refused lines are as useful as the successful one.

Pointing the scan at a remote host proves that the service behind the port accepted the connection, which is a different question from whether the host answers at all.

Terminal showing nc -zv linuxfordevices.com 443 reporting that the connection to port 443 succeeded
The same check against a remote host confirms that the service behind port 443 accepted the connection.

A refused connection is not proof that a service is down. A firewall that drops the packet instead of rejecting it makes netcat wait for the timeout, which is why a scan that hangs is a firewall and SELinux question before it is a netcat question. A listener bound to 127.0.0.1 also refuses a scan sent to the machine’s public address.

Read what a service sends back

An open port only tells you something is listening. Send a request and read the answer to find out what it is.

printf 'GET / HTTP/1.0\r\nHost: example.com\r\n\r\n' | nc -w 6 example.com 80 | head -8
Terminal showing a raw HTTP request sent through netcat returning the 200 OK status line and server headers
The status line and headers arrive exactly as the server writes them, which is the point of using netcat here.

The status line and the Server header come back exactly as the service writes them, which is how you confirm that a proxy or CDN sits in front of a host. The newline characters are part of the protocol, and a request that ends without its blank line gets no reply at all.

A service that greets clients first needs no request. OpenSSH writes its version string the moment the connection opens, so a bare connect is enough to identify it.

nc -w 4 127.0.0.1 22
Terminal showing netcat reading the OpenSSH version banner from port 22
OpenSSH announces itself before the client sends anything, so a bare connect is enough to identify the service.

When you want the body of a page rather than its headers, an HTTP client is shorter and handles redirects for you, and downloading a file with curl covers the request flags that netcat cannot tell you about.

Move a file between two machines

Netcat copies a file by piping bytes into a connection on one side and out of a listener on the other. There is no encryption and no checksum, so this suits a trusted network and nothing else.

printf 'netcat file transfer payload\n' > /tmp/nc-payload.txt; nc -l 9005 > /tmp/nc-received.txt & sleep 0.5; nc -q 2 127.0.0.1 9005 < /tmp/nc-payload.txt; wait; diff /tmp/nc-payload.txt /tmp/nc-received.txt && echo 'files are identical'
Terminal showing a netcat file transfer verified with diff reporting the files are identical
A silent diff plus the confirmation line means the bytes arrived unchanged.

The diff prints nothing and the confirmation line prints, which means the bytes arrived unchanged. Across machines the order matters, because the receiver has to be listening before the sender connects.

  1. Start the receiver and give it a file to write into. nc -l 9005 > received.txt
  2. Start the sender and feed it the file. nc -q 2 192.168.1.20 9005 < payload.txt
  3. Compare the payload with the copy that arrived. diff payload.txt received.txt

Anything crossing an untrusted path should use an encrypted transfer instead, and a plain download from a URL does not need a listener at all. Setting up an SFTP client keeps the same shape as the commands above, and downloading a file with wget is the shorter route when the file already lives on a web server.

Keep a listener alive for repeated connections

A listener without -k accepts one connection and exits, which is the reason a second client gets a refusal on a port that was working a minute ago.

nc -lk 9006 > /tmp/nc-keepopen.txt & L=$!; sleep 0.5; printf 'first connection\n' | nc -q 1 127.0.0.1 9006; sleep 1; printf 'second connection\n' | nc -q 1 127.0.0.1 9006; sleep 0.5; kill $L; cat /tmp/nc-keepopen.txt
Terminal showing a keep-open netcat listener capturing two separate client connections
With -k the listener survives the first client, so both lines land in the same file.

Both lines land in the same file because the listener stayed up between them. The -k flag is what turns nc into a small service you can test against, so the process now keeps running until you stop it.

When a client cannot connect, look at the socket before you blame the client. A listener that already exited and a listener that never started produce the same refusal, and only the socket table tells them apart, so reading listening sockets with ss and netstat is the check to run next. It is also the fastest way to confirm that a container published its port to the host.

Send UDP datagrams instead of TCP

Add -u on both ends to move from a byte stream to datagrams. A UDP listener has nothing to accept, because no connection is ever established.

nc -lu 9007 > /tmp/nc-udp.txt & L=$!; sleep 0.5; printf 'udp datagram\n' | nc -u -q 1 127.0.0.1 9007; sleep 0.3; kill $L; cat /tmp/nc-udp.txt
Terminal showing a UDP netcat listener receiving a datagram on port 9007
The -u flag on both ends is what makes the datagram arrive.

Nothing confirms delivery, because the receiving end never acknowledges a datagram. If the line does not appear, the packet either went to the wrong port or was dropped on the way.

  • The flag is needed on the sender and on the listener, and dropping it on either end gives you a silent mismatch between TCP and UDP.
  • -k with -u keeps one socket open for datagrams from more than one host.
  • A closed UDP port sends no refusal message, so netcat reports nothing rather than an error.

Options that were removed

The backdoor one-liner that appears in older netcat guides does not run on the nc that ships with Ubuntu or Debian.

nc -w 3 -e /bin/sh 127.0.0.1 9001 2>&1
Terminal showing nc rejecting the -e option with an invalid option error and printing its usage block
netcat-openbsd rejects -e outright and prints the option list it will accept.

OpenBSD nc has no -e option at all, so the shell redirect that those guides rely on is gone from the default binary. The same holds for a handful of other traditional flags, and the usage block netcat prints when it rejects an option is the authoritative list for your build.

Traditional flagWhat it didWhere it still exists
-e programredirect the socket to a programncat –sh-exec
-c commandsrun a shell command after connectingncat –sh-exec
-o filewrite a hex dump of the traffictcpdump or socat
-g and -Gsource-route packets over IPv4removed everywhere

The behavior behind -e is a genuine security problem, and removing it from the default binary was deliberate. If you need to attach a program to a socket, install ncat and read its own option list rather than assuming the flag survived.

Frequently asked questions

The answers below settle which command to reach for, and each one matches the nc on a current Debian or Ubuntu system.

What is the netcat command in Linux?

Netcat is a command-line tool that reads and writes raw data over TCP, UDP, and UNIX-domain sockets. The name nc usually points to netcat-openbsd on Debian and Ubuntu, and to ncat on Fedora and RHEL.

How do I check whether a port is open with netcat?

Run nc -zv host port and read the exit status. A status of 0 means something accepted the connection, and a status of 1 means the port refused it or never answered.

Why does my nc client hang after sending a line?

The client waits for the connection to close after its input ends. Add -q 1 on the sender, or -N to shut the socket down as soon as standard input reaches end of file.

Why does nc -l -p give an error on my system?

Listen mode takes the port as a positional argument, and netcat-traditional is the variant that requires -p. If you see an error, run nc -h and match your command to the option list that build actually prints.

Can netcat transfer files securely?

No. Netcat sends the file as plain bytes with no encryption and no integrity check. Use scp or sftp whenever the transfer crosses a network you do not control.