Troubleshooting

ping: command not found? Install it on any Linux, and fix Operation not permitted

ping: command not found? Install iputils-ping on Ubuntu and Debian or iputils on RHEL, add it to Docker images, and fix socket: Operation not permitted.

Published ~9 min read
On this page

Short answer: ping: command not found means ping is not installed. Minimal installs and nearly every container image leave it out, and the package is not called ping: on Debian and Ubuntu it is iputils-ping, on Rocky, AlmaLinux and Fedora iputils, and Alpine already has a BusyBox ping. If the message ends in Operation not permitted instead, ping is installed but may not open its socket; that has a fix of its own.

Debian · Ubuntu
sudo apt update
sudo apt install -y iputils-ping

The exact wording tells you which shell or tool printed the error, and that usually tells you the cause. Find your message in the table and jump to its section.

Which error do you see?

MessagePrinted byCause and fix
bash: ping: command not foundbash in a terminal window; with a leading -bash: in an SSH session (a login shell)Not installed. Install ping
zsh: command not found: pingzsh, the default shell on macOSOn macOS, which ships ping in /sbin, a broken PATH: repair PATH. On Linux, not installed: install ping
/bin/sh: 1: ping: not founddash (Debian, Ubuntu) in a Dockerfile RUN line or a cron job; a #!/bin/sh script prints its own name and line instead, as in ./check.sh: 2: ping: not foundThe image or system has no ping. Docker
Command 'ping' not found, but can be installed with:Ubuntu's command-not-found helperNot installed. Take the iputils-ping line. Ubuntu
exec: "ping": executable file not found in $PATHdocker exec, kubectl exec, a container health checkThe image has no ping. Docker
bash: ping6: command not foundbash, running a script written for the old separate ping6Use ping -6. ping6
ping: socket: Operation not permittediputils ping without the right to open a socket; as a normal user it adds ping: => missing cap_net_raw+p capability or setuid?Installed, no permission. Permission fix
bash: /usr/bin/ping: Operation not permittedbash, when the kernel refuses to start a ping that carries a file capability, typical in a container that drops NET_RAWInstalled, capability refused. Docker and Kubernetes
ping: permission denied (are you root?)BusyBox ping on Alpine, run as a non-root userNo raw socket allowed. Permission fix
'ping' is not recognized as an internal or external command,Windows cmdA PATH that lost System32. Windows

The bash, dash and iputils lines were reproduced on Debian 12 with bash 5.2.15, dash 0.5.12 and iputils 20221126. A missing ping ends the command with exit status 127, a refused socket with 2 and a refused start with 126. The zsh, BusyBox, Ubuntu helper and Windows lines are those tools’ standard wording.

First: which system are you on?

If you are not sure what you are logged into, ask the system. The package manager is what matters, not the marketing name.

any Linux shell
grep -E '^(ID|VERSION_ID)=' /etc/os-release
Example output · Debian 12
VERSION_ID="12"
ID=debian

debian and ubuntu use apt, alpine uses apk, rocky, almalinux, rhel and fedora use dnf.

Installing ping

Debian and Ubuntu: iputils-ping

Debian · Ubuntu
sudo apt update
sudo apt install -y iputils-ping

Do not type apt install ping. In Debian 12’s package lists, ping is a virtual name that two packages provide, iputils-ping and GNU’s inetutils-ping, so apt will not choose for you:

Example output · Debian 12, apt-get -s install ping
Package ping is a virtual package provided by:
  iputils-ping 3:20221126-1+deb12u1
  inetutils-ping 2:2.4-2+deb12u3

E: Package 'ping' has no installation candidate

Take iputils-ping: it is the one Debian installs by default, and its options (-c, -W, -M do) are the ones in the ping command guide. inetutils-ping takes partly different options, so scripts written for iputils can break on it.

Why it is missing: Debian gives iputils-ping the priority important (dpkg-query shows it on Debian 12), so every system set up with the installer has it. Container images are built from the much smaller set of required packages, which is why the debian and ubuntu images answer ping: command not found. On Ubuntu, an interactive shell may print the command-not-found helper instead, Command 'ping' not found, but can be installed with: followed by apt lines: take the iputils-ping one.

If apt update fails with Temporary failure resolving, the server cannot reach DNS, which no package fixes; see Temporary failure in name resolution. If Unable to locate package iputils-ping stays after an update, see E: Unable to locate package.

Alpine: BusyBox ping or iputils

The alpine image has ping as a BusyBox applet, so a plain Alpine container rarely says “not found”. It does when the image has no BusyBox at all (distroless images, FROM scratch), and BusyBox’s ping lacks many iputils options. The full version, as root:

Alpine
apk add iputils
Dockerfile · Alpine
RUN apk add --no-cache iputils

Rocky, AlmaLinux, RHEL and Fedora

Rocky · Alma · RHEL · Fedora
sudo dnf install -y iputils

Red Hat’s ubi-minimal images have only microdnf (microdnf install -y iputils && microdnf clean all), and CentOS 7 and RHEL 7 use sudo yum install -y iputils.

Arch and openSUSE

Arch · openSUSE
sudo pacman -S --needed iputils     # Arch, Manjaro
sudo zypper install -y iputils      # openSUSE

ping6: command not found

iputils folded ping6 into ping: ping -6 HOST sends ICMPv6, and plain ping uses IPv6 by itself when you give it an IPv6 address. Debian 12 still ships ping6 as a link to ping, but other systems dropped it. Change old scripts to ping -6 rather than hunting for a package.

Inside a Docker container

In a container you are usually root already, so there is no sudo, and the package index is empty. Called from outside, the runtime reports the missing binary in its own words:

docker exec · example output
OCI runtime exec failed: exec failed: unable to start container process: exec: "ping": executable file not found in $PATH: unknown

For a one-off test, install it in the running container:

Debian or Ubuntu based image
apt-get update && apt-get install -y iputils-ping

Anything installed by hand is gone when the container is recreated, so put it in the Dockerfile if the image needs ping for good:

Dockerfile
FROM debian:12-slim
RUN apt-get update \
 && apt-get install -y --no-install-recommends iputils-ping \
 && rm -rf /var/lib/apt/lists/*

Debian 12’s install script for the package gives ping the cap_net_raw file capability with setcap (its package, libcap2-bin, is a dependency of iputils-ping there). If setcap is missing or fails, for example on a build file system without extended attributes, the script makes ping setuid root instead and prints Setcap failed on /bin/ping, falling back to setuid or Setcap is not installed, falling back to setuid. Either way the container can ping.

Often you do not need ping in the image at all. To look at a container’s network, run the tools from the host inside its network namespace with nsenter, as shown in ifconfig: command not found.

ping: socket: Operation not permitted

This one is not a missing program. Linux lets ping send echo requests in two ways: a raw socket, which needs the CAP_NET_RAW capability, or an ICMP datagram socket, which a process may open if its group ID falls inside net.ipv4.ping_group_range. The ping man page lists exactly those cases. When neither works, iputils stops with exit status 2:

Example output · Debian 12, iputils 20221126, normal user
ping: socktype: SOCK_RAW
ping: socket: Operation not permitted
ping: => missing cap_net_raw+p capability or setuid?

We reproduced that on Debian 12 by copying the ping binary with a plain cp and running the copy as the nobody user. Older iputils releases word it ping: icmp open socket: Operation not permitted, and BusyBox says ping: permission denied (are you root?).

The kernel’s default for ping_group_range is 1 0, an empty range: according to the kernel’s sysctl documentation, nobody, not even root, may then create ping sockets. Debian 12 keeps that default and gives the ping binary the capability instead. systemd’s own sysctl defaults open the range to every group, so on distributions that ship that file any user can ping without a capability. Check which case you are in:

Linux
p=$(readlink -f "$(command -v ping)")
getcap "$p"                          # the file capability, if any
ls -l "$p"                           # an s, as in -rwsr-xr-x, means setuid root
sysctl net.ipv4.ping_group_range     # 1 0 means no ICMP datagram sockets for anyone
id -g                                # your group ID
Example output · Debian 12, as the nobody user
/usr/bin/ping cap_net_raw=ep
-rwxr-xr-x 1 root root 90568 Sep 24  2024 /usr/bin/ping
net.ipv4.ping_group_range = 1	0
65534

That ping works for every user, nobody (group 65534) included, because of its capability. Without it, and with the range at 1 0, only root could ping. Pick one of two fixes.

Fix 1: give ping its capability back

Debian · Ubuntu
sudo apt install -y libcap2-bin       # provides setcap, if it is missing
sudo setcap cap_net_raw+ep "$(readlink -f "$(command -v ping)")"

# or let the package do it again
sudo apt install --reinstall iputils-ping

On Rocky, Alma, RHEL and Fedora the reinstall is sudo dnf reinstall -y iputils. The capability lives in an extended attribute of the file, and copies lose it. On Debian 12 with GNU coreutils 9.1 and GNU tar 1.34, a plain cp and a default tar both dropped it, while cp --preserve=xattr and tar --xattrs --xattrs-include='security.capability' kept it. A ping that was copied into a chroot, an image layer or a restored backup is the usual suspect.

Fix 2: allow ICMP datagram sockets

Linux
sudo sysctl -w net.ipv4.ping_group_range="0 2147483647"
echo 'net.ipv4.ping_group_range = 0 2147483647' | sudo tee /etc/sysctl.d/60-ping.conf

The first line takes effect at once, the second keeps it after a reboot. 0 2147483647 is the range systemd uses; the kernel documentation also shows a single group, 100 100, if you want to allow ping for one group only. An ICMP datagram socket can only send and receive echo messages, so this gives users ping, not raw packet access.

In Docker and Kubernetes

Docker keeps NET_RAW in its default capability set, and current Docker Engine releases also open ping_group_range inside containers, so ping usually works there once it is installed. It breaks when capabilities are dropped. A ping binary that carries a file capability is then refused before it even starts:

Example output · Debian 12, CAP_NET_RAW dropped
bash: line 1: /usr/bin/ping: Operation not permitted

We reproduced that on Debian 12 by dropping CAP_NET_RAW from the bounding set with setpriv, which is what --cap-drop NET_RAW does to a container. It is the safety check described in capabilities(7): a program marked to receive a capability is not started at all if the kernel cannot grant it, and the shell reports exit status 126. Two ways out:

  • Give the capability back: docker run --cap-add NET_RAW, or NET_RAW under capabilities.add in a Kubernetes container’s securityContext.
  • Or drop it from the binary with setcap -r in the Dockerfile and let ping use a datagram socket: docker run --sysctl net.ipv4.ping_group_range="0 2147483647", or the pod setting below, where net.ipv4.ping_group_range is one of Kubernetes’ safe sysctls.
Kubernetes · pod spec
spec:
  securityContext:
    sysctls:
      - name: net.ipv4.ping_group_range
        value: "0 2147483647"

When ping is installed but still “not found”

Check that the file exists first. On Debian 12, /bin is a link to /usr/bin, so ping is /usr/bin/ping; Rocky, Alma and Fedora also use /usr/bin/ping; macOS keeps it in /sbin/ping. If the file is there and the shell still refuses:

  • The shell remembers an old location. Run hash -r in bash or rehash in zsh, or open a new shell.
  • A startup file overwrote PATH. If ls and grep are missing too, a line such as export PATH=/opt/tool/bin without :$PATH replaced the whole search list. On a Mac it only takes a PATH without /sbin to get zsh: command not found: ping. Restore PATH for this session, then fix the line in ~/.bashrc, ~/.profile, ~/.zshrc or ~/.zprofile.
Linux · bash · zsh
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
macOS · zsh
export PATH=/usr/bin:/bin:/usr/sbin:/sbin

ping on Windows

Every Windows and Windows Server release ships ping.exe in C:\Windows\System32. In cmd, a missing ping reads:

cmd · example output
'ping' is not recognized as an internal or external command,
operable program or batch file.

That means the PATH no longer contains System32, usually after an installer rewrote it. Run ping by its full path to confirm, then repair the system Path under System Properties → Environment Variables; it should contain %SystemRoot%\system32.

cmd
C:\Windows\System32\ping.exe 1.1.1.1
echo %PATH%

PowerShell has its own Test-Connection 1.1.1.1 -Count 4, and Test-NetConnection HOST -Port 443 tests a TCP port instead. Inside WSL you are on Linux, so the sections above apply.

Verify that it worked

Linux
command -v ping
ping -V
ping -c 3 1.1.1.1; echo "exit status: $?"
Example output · Debian 12, ICMP filtered on the path
/usr/bin/ping
ping from iputils 20221126
libcap: yes, IDN: yes, NLS: no, error.h: yes, getrandom(): yes, __fpending(): yes
PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.

--- 1.1.1.1 ping statistics ---
3 packets transmitted, 0 received, 100% packet loss, time 2040ms

exit status: 1

The first line is the path the shell runs, the next two the version and its build options. Then ping ran for real and got no replies, and the exit status says why: per the man page, 1 means ping worked but nothing answered, while 2 would be an error such as the socket problem above. Here something on the path dropped the ICMP replies, which is a firewall question, not an installation problem. Why that happens and how to test the port instead is in the ping command guide.

  • 0: replies arrived.
  • 1: ping ran, but no reply came back in time.
  • 2: an error, such as socket: Operation not permitted.
  • 126: the shell could not start ping, as with a refused capability.
  • 127: command not found.

If you cannot install anything

ICMP needs a privileged binary; a TCP connection test needs nothing but bash. It answers the question most people ask ping (“is the server up?”), as long as you pick a port the server listens on:

bash
timeout 3 bash -c '</dev/tcp/1.1.1.1/443' && echo "port 443 reachable"
Example output · Debian 12
port 443 reachable

With curl on the box, curl -sS -o /dev/null -w 'connect: %{time_connect}s\n' https://1.1.1.1/ prints how long the TCP connection took, a fair stand-in for a round trip. To measure from the outside, the ping test times the round trip from your browser to Amsterdam and sends a real ICMP ping from Amsterdam back to your address.

A note on fresh servers

On a server you control, the one-line install is all it takes, and the rest of the base setup (a non-root user, key-only SSH, automatic security updates) is in the initial server setup checklist. Need a box to try this on? An Ubuntu VPS or any other Linux VPS on the Standard KVM line gives you root, so neither a missing package nor a missing capability stands in your way for long.

Another tool missing, or a directory to add to PATH for good in bash, zsh and fish? See command not found: the three causes and the fix for every tool.

Frequently asked

Which package provides ping on Ubuntu and Debian?

iputils-ping. 'apt install ping' fails with 'Package ping is a virtual package provided by' and 'has no installation candidate', because both iputils-ping and GNU's inetutils-ping provide the name ping and apt will not pick one. Install iputils-ping: Debian installs it by default, and its options are the ones most guides use.

Why is ping missing in my Docker container?

Container images are built from a minimal package set, and the debian and ubuntu images leave iputils-ping out. Add it in the Dockerfile with 'apt-get install -y --no-install-recommends iputils-ping' ('apk add --no-cache iputils' on Alpine, which already has a BusyBox ping) so it survives a rebuild.

What does ping: socket: Operation not permitted mean?

ping is installed but may open neither a raw socket, because it lacks the CAP_NET_RAW capability, nor an ICMP datagram socket, because your group is outside net.ipv4.ping_group_range. Restore the capability with 'sudo setcap cap_net_raw+ep' on the ping binary or reinstall the package, or widen ping_group_range with sysctl.

Related articles

All troubleshooting