Three of the most common error messages on a Linux box are really the same question wearing different clothes:

  • bind: Address already in use — something already has that port
  • umount: target is busy — something is still inside that mount point
  • df says the disk is full but du cannot find the space — something is holding a file you already deleted

The question in all three cases is which process has this open, and lsof is the tool that answers it. The name is “list open files”, which undersells it, because on Linux nearly everything is a file — sockets, pipes, devices and directories all count.

Installing it

It is not always present on a minimal server image.

sudo apt install lsof psmisc      # Debian, Ubuntu
sudo dnf install lsof psmisc      # Fedora, RHEL, Rocky, Alma
sudo pacman -S lsof psmisc        # Arch

psmisc brings fuser, which does a narrower job in a shorter line. On Alpine, lsof is in the main repository but the busybox fuser is more limited.

Run it as root

Without sudo, lsof can only see your own processes, and it will not tell you that it is hiding things — it prints a partial answer that looks complete. This is the single most common reason someone concludes “nothing has the port open” when something clearly does.

What has this port?

sudo lsof -i :8080

That lists every process with something on port 8080, in or out. To narrow it to the thing actually listening:

sudo lsof -i :8080 -sTCP:LISTEN

# everything listening anywhere, which is a useful audit
sudo lsof -i -P -n | grep LISTEN

-P stops it translating port numbers into service names (so you see :8080 rather than :http-alt) and -n stops it doing reverse DNS on every address. Together they make the output both faster and easier to read, and you will want them almost every time.

The modern alternative for ports specifically is ss, which is quicker:

sudo ss -tulpn | grep :8080

Use ss when the question is only about network sockets. Use lsof when the question might be about anything else, which is most of the time.

What is keeping this mount busy?

sudo lsof +D /mnt/backup      # everything under the directory
sudo fuser -vm /mnt/backup    # everything using that mount point

+D walks the whole tree, which is thorough and slow on a large mount. fuser -vm asks a different question — what is using this filesystem — and answers it almost instantly, which usually makes it the better first attempt for a stuck umount.

The answer is frequently a shell someone left sitting in the directory, including your own. A process whose working directory is inside the mount counts as using it, even if it has no files open.

The disk that is full of nothing

Deleting a file does not free the space if something still has it open. Unlinking removes the name from the directory; the data survives until the last file descriptor pointing at it is closed. So a log file someone deleted to “free up space” while the service is still writing to it stays on disk, invisible to du, until that service is restarted. This is why df and du disagree, and it is almost always the answer when they do.

Find them:

sudo lsof +L1

+L1 means “files with fewer than one link” — deleted, but still held. The SIZE/OFF column tells you how much space you get back, and restarting the process named in the COMMAND column is what actually releases it.

If a restart is genuinely not possible right now, you can truncate the file through its descriptor. The process keeps writing at its old offset, so the file will appear sparse afterwards, but the space comes back immediately:

# PID 1234, file descriptor 5, from the lsof output
sudo truncate -s 0 /proc/1234/fd/5

Treat that as a way to survive until a maintenance window, not as the fix.

The other questions worth knowing

QuestionCommand
What does this process have open?sudo lsof -p 1234
What has this exact file open?sudo lsof /var/log/app.log
What is this user running, and with what open?sudo lsof -u deploy
Everything a named program has opensudo lsof -c nginx
Which process is talking to this hostsudo lsof -i @10.0.0.5
Only IPv4, only IPv6lsof -i4 / lsof -i6
Everything except this usersudo lsof -u ^root

By default multiple conditions are combined with OR, not AND, which surprises people. lsof -u deploy -i :443 shows everything deploy has open plus everything on 443. Add -a to mean AND:

sudo lsof -a -u deploy -i :443

Reading the output

ColumnMeans
COMMANDThe program name, truncated to nine characters by default (+c 0 shows it in full)
PIDProcess ID — what you feed to systemctl status or kill
USERWho it runs as
FDDescriptor number, plus cwd, txt, mem, rtd; u is read/write, r read, w write
TYPEREG file, DIR directory, IPv4/IPv6 socket, unix socket, FIFO pipe
NAMEThe path, or the connection — and (deleted) when the file is gone but held

An FD of cwd is the one to look for when a mount will not unmount: that process is not using a file, it is simply standing there.

fuser, for when you already know what you want to do

fuser is smaller and blunter. Where lsof describes, fuser can act.

fuser -v /var/log/app.log        # who has this file, with names
fuser -vm /mnt/backup            # who is using this filesystem
fuser -v -n tcp 8080             # who has this TCP port
sudo fuser -k -TERM /mnt/backup  # ask them all to stop

fuser -k kills processes. Without a signal argument it sends SIGKILL, which gives the process no chance to flush anything to disk. Always look first with -v, and if you do use it, prefer -TERM. Running fuser -k on a mount that turns out to contain a database directory is a bad afternoon.

Common problems

SymptomCauseFix
Empty output when something obviously has the portNot running as rootAdd sudo
lsof: WARNING: can't stat() fuse.gvfsd-fuseA user filesystem it cannot readHarmless — add -w to silence warnings
Takes many seconds to returnReverse DNS on every addressAdd -n, and -P for ports
Port free according to lsof, still cannot bindSocket in TIME_WAIT, or a container publishing itss -tan | grep 8080; check docker ps
umount still busy with nothing listedAn NFS server or a kernel thread holds itumount -l to detach lazily, then investigate
Two filters returned far too muchConditions default to ORAdd -a

Quick reference

sudo lsof -i :8080 -sTCP:LISTEN   # what is on this port
sudo lsof -i -P -n | grep LISTEN  # everything listening
sudo lsof +L1                     # deleted files still holding space
sudo lsof +D /mnt/backup          # everything under a directory
sudo fuser -vm /mnt/backup        # what is using a mount, fast
sudo lsof -p 1234                 # what one process has open
sudo lsof -c nginx                # what a named program has open
sudo lsof -a -u deploy -i :443    # AND, not OR
sudo truncate -s 0 /proc/1234/fd/5  # emergency space, not a fix

Related reading