Guides

lsof command: find what uses a port, a file or deleted disk space

The lsof command lists open files and their processes: lsof -i :PORT, -p PID, -u user, +D dir, deleted files with lsof +L1, and lsof with kill.

Published ~8 min read
On this page

Short answer: lsof lists open files and the processes that hold them, and on Linux sockets count as files. So sudo lsof -i :8080 shows what is using a port, sudo lsof -p PID everything one process has open, sudo lsof +D /path who is using a directory, and sudo lsof +L1 deleted files that still take up disk space. Run it with sudo: without root, lsof cannot read the open files of other users’ processes, so their sockets are simply missing from lsof -i.

Linux
sudo lsof -i :8080        # what uses port 8080
sudo lsof -p 1234         # every file PID 1234 has open
sudo lsof +L1             # deleted files that are still open

Minimal Debian and Ubuntu installs do not include it: sudo apt install lsof, or sudo dnf install lsof on Rocky and AlmaLinux. The examples marked as real output were run on Debian 12 with lsof 4.95.0, against a test process that held a 10 MB file open; the rest follows the lsof man page.

lsof cheat sheet

TaskCommand
What uses a port, in any statesudo lsof -i :8080
Only the listening TCP socketsudo lsof -nP -iTCP:8080 -sTCP:LISTEN
Every listening TCP portsudo lsof -nP -iTCP -sTCP:LISTEN
All network connectionssudo lsof -nP -i
Connections to or from one hostsudo lsof -nP -i @203.0.113.10
Files of one processsudo lsof -p 1234
Files of every process with a namesudo lsof -c nginx
Files of one usersudo lsof -u www-data
Everyone except rootsudo lsof -u ^root
Who has this file opensudo lsof /var/log/nginx/access.log
Who uses anything under a directorysudo lsof +D /var/www
Deleted files still holding spacesudo lsof +L1
PIDs only, for scriptssudo lsof -t -i :8080
Combine conditions with ANDsudo lsof -a -u www-data -i
Repeat every 2 secondssudo lsof -r 2 -i :443

Add -n and -P to almost everything that touches the network: -n stops lsof looking up host names and -P keeps port numbers as numbers (443 instead of https). Both make it faster and the output easier to grep.

Reading lsof output

This is real output for the test process, a sleep started with a log file open on descriptor 3. The test directory is shortened to /tmp/lsof-test, and the locale files mapped into memory are left out:

Real output · sudo lsof -p 3897237, Debian 12
COMMAND     PID USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
sleep   3897237 root  cwd    DIR    8,1     4096 3673507 /tmp/lsof-test
sleep   3897237 root  rtd    DIR    8,1     4096       2 /
sleep   3897237 root  txt    REG    8,1    43888     672 /usr/bin/sleep
sleep   3897237 root  mem    REG    8,1  1926232    9755 /usr/lib/x86_64-linux-gnu/libc.so.6
sleep   3897237 root  mem    REG    8,1   215000    9751 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2
sleep   3897237 root    0r   CHR    1,3      0t0       4 /dev/null
sleep   3897237 root    1w   CHR    1,3      0t0       4 /dev/null
sleep   3897237 root    2w   CHR    1,3      0t0       4 /dev/null
sleep   3897237 root    3w   REG    8,1 10485760 3673780 /tmp/lsof-test/app.log
  • COMMAND, PID, USER: the process. COMMAND is cut to nine characters unless you widen it with +c 15.
  • FD: a descriptor number with its mode (r read, w write, u both), or a word for things that are not descriptors: cwd the working directory, rtd the root directory, txt the program itself, mem a file mapped into memory, such as a shared library.
  • TYPE: REG a regular file, DIR a directory, CHR a character device, IPv4 and IPv6 network sockets, unix a local socket, FIFO a pipe.
  • SIZE/OFF: the file size in bytes, or an offset where size means nothing; 0t0 is offset 0, written in decimal.
  • NODE and NAME: the inode and the path, or for a socket the protocol and the addresses.

Only the numbered lines are file descriptors, which is why lsof -p PID | wc -l overcounts. To count descriptors against a limit, use ls /proc/PID/fd | wc -l, as shown in too many open files. Plain lsof with no options is worse still: on Debian 12 it adds TID and TASKCMD columns and repeats the files of every thread, so its line count says little about anything.

lsof -i: which process uses a port

Linux
sudo lsof -i :443                       # every socket with port 443 on either end
sudo lsof -nP -iTCP:443 -sTCP:LISTEN    # just the service listening on 443
sudo lsof -nP -iUDP:53                  # UDP sockets on port 53
sudo lsof -nP -i4TCP:1-1024             # IPv4 TCP sockets on ports 1 to 1024
Example output · sudo lsof -nP -i :443 (addresses and PIDs are examples)
COMMAND  PID     USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
nginx   1340     root    6u  IPv4  24118      0t0  TCP *:443 (LISTEN)
nginx   1341 www-data    6u  IPv4  24118      0t0  TCP *:443 (LISTEN)
nginx   1341 www-data   12u  IPv4  91822      0t0  TCP 203.0.113.10:443->198.51.100.7:52114 (ESTABLISHED)
https   2210     _apt    5u  IPv4  93310      0t0  TCP 203.0.113.10:41870->192.0.2.80:443 (ESTABLISHED)

-i :443 matches the port on either end of a socket, so it also lists your server’s own outgoing connections to port 443 somewhere else, like the apt download (its https helper, running as _apt) in the last line. When you are looking for the program that holds a port, add the state filter, written as the man page does with the protocol in -i too: -iTCP:443 -sTCP:LISTEN. The general form of the address is [4|6][protocol][@host][:port], every part optional, so -i4TCP:1-1024 is one address and not two options. ss answers the same question faster and is preinstalled on current distributions; both are covered in checking open ports on Linux.

Files of a process, a command or a user

Linux
sudo lsof -p 1340              # one PID (several: -p 1340,1341)
sudo lsof -c php-fpm           # every process whose name starts with php-fpm
sudo lsof -u www-data          # everything a user has open
sudo lsof -u ^root -i          # network files of everyone except root

The -a trap: lsof joins options with OR

By default lsof lists a file if it matches any of your options, not all of them. sudo lsof -u www-data -i therefore prints every file of www-data plus every network socket of every user, which is rarely what anyone means. -a switches to AND, and it applies to all options at once, wherever you put it:

Linux
sudo lsof -a -u www-data -i       # network sockets of www-data only
sudo lsof -a -p 1341 -d 0-20      # descriptors 0 to 20 of one process

On the test system, lsof -a -p PID -c cron for the sleep process returned nothing, as it should: no process is both that PID and named cron. Exclusions such as -u ^root are the exception; they always apply first.

Who is using a file or a directory

Linux
sudo lsof /var/lib/dpkg/lock-frontend   # who holds the apt lock
sudo lsof +D /srv/data                  # anything open below /srv/data, recursively
sudo lsof +d /srv/data                  # only files directly in /srv/data
sudo lsof /mnt/backup                   # a mount point: every open file on that filesystem

+D walks the whole tree and checks every file in it, which takes a while on a directory with millions of files; +d stays at one level. Naming a mount point instead of a directory makes lsof list every open file on that filesystem, which is the quickest answer to umount: target is busy. The usual culprits are a shell whose working directory is inside the mount (FD cwd) and a service writing a log there. fuser -vm /mnt/backup, from psmisc, gives the same answer in a shorter form. The apt lock line is the first step in Could not get lock.

Deleted files that still use disk space: lsof +L1

Deleting a file only removes its name. As long as a process keeps the file open, the kernel keeps the data, and the space stays used: df reports the disk full while du cannot find the files. +L1 lists open files with a link count below one, which means files that no longer have a name. This is the test process again, after rm app.log:

Real output · sudo lsof -a -p 3897237 +L1, Debian 12
COMMAND     PID USER   FD   TYPE DEVICE SIZE/OFF NLINK    NODE NAME
sleep   3897237 root    3w   REG    8,1 10485760     0 3673780 /tmp/lsof-test/app.log (deleted)

All 10 MB still sit on the disk, owned by PID 3897237 through descriptor 3. On a real server the list is sorted by size to find the big ones; with +L1 the size is the seventh column, because lsof adds NLINK after it:

Linux
sudo lsof -nP +L1 | sort -k7 -rn | head
sudo lsof -nP +aL1 /           # only deleted files on the root filesystem

Two ways to get the space back:

  • Restart or reload the process that holds the file. Once it closes the descriptor, the space is free. For a log, a reload usually makes the program reopen its log files, which is what logrotate’s postrotate scripts trigger.
  • Truncate it through /proc when a restart is not possible: sudo truncate -s 0 /proc/PID/fd/FD. On the test process, : > /proc/3897237/fd/3 took SIZE/OFF from 10485760 to 0 without stopping it.

DEL in the output is a related case: a library or program file that was replaced by an update while a running process still has the old copy mapped into memory. sudo lsof -n | grep -w DEL after an upgrade shows which services still run old code and need a restart. The full disk-full checklist, with this step in it, is in No space left on device, and why df and du disagree explains the numbers.

lsof and kill

-t prints only PIDs, one per line and without a header, which is made for passing on to kill:

Linux
sudo lsof -nP -iTCP:8080 -sTCP:LISTEN          # look first
sudo kill $(sudo lsof -t -iTCP:8080 -sTCP:LISTEN)
sudo lsof -t +D /mnt/backup | xargs -r sudo kill   # everything still using a mount

Look before you kill. lsof -t -i :8080 without the state filter also returns any client that happens to be connected to port 8080 somewhere else, and a kill with no PIDs at all fails with an error; xargs -r skips the call when lsof finds nothing. On the test system, kill $(lsof -t -a -p PID -d 3) ended the sleep process as expected. Which signal to send, and what to do when a process ignores it, is in how to kill a process in Linux.

When lsof is slow or noisy

  • It reads every process. Narrow the search with -p, -i or a path, and add -n -P. A full lsof on a busy server takes a while and prints far more than you can read.
  • It hangs on a dead network mount. A stuck NFS or SSHFS mount can block lsof; -b avoids the kernel calls that block, at the price of less detail.
  • Warnings about other filesystems. Lines starting with lsof: WARNING: can’t stat() are mounts lsof is not allowed to look into; -w hides them. -t already implies -w.

lsof on macOS

macOS ships lsof, and the -i, -p, -u, -t and +L1 commands above work the same (there is no /proc to truncate through, though). It is the standard way to find the program behind a port on a Mac, because the macOS netstat has no process column by default: sudo lsof -nP -iTCP -sTCP:LISTEN lists every listening port with its program.

Frequently asked

How do I find which process is using a port with lsof?

sudo lsof -i :8080 lists every socket with port 8080 on either end, including outgoing connections. For only the program listening on it, use sudo lsof -nP -iTCP:8080 -sTCP:LISTEN; -n and -P keep addresses and ports numeric, which is also faster.

How do I find deleted files that still use disk space?

sudo lsof +L1 lists open files whose link count is below one, meaning they were deleted while a process still holds them open. Restart or reload that process to free the space, or truncate a log through /proc/PID/fd/FD when a restart is not possible.

Why does lsof show more lines than a process has open files?

lsof also lists the working directory, the root directory, the program binary and memory-mapped libraries, none of which uses a file descriptor, and plain lsof with no options repeats the files for every thread. Count real descriptors with ls /proc/PID/fd | wc -l instead.

Why does lsof -u www-data -i show other users' sockets?

lsof joins selection options with OR by default, so that command lists every file of www-data plus every network socket on the system. Add -a to require all conditions at once: sudo lsof -a -u www-data -i.

Related articles

All guides