lsof Explained: Finding What Has a File, Port, or Mount Open
Linux represents almost everything as a file. Network sockets are files. Pipes are files. Devices are files. The directory your shell is sitting in is a file. That design decision is why one command can answer an unrelated-looking set of questions, and lsof is that command.
The basic shape
sudo lsof
Run alone it prints every open file descriptor on the system, which is thousands of lines and not useful. The value is in the filters.
The columns worth knowing: COMMAND and PID identify the process, USER its owner, FD the file descriptor number and mode, TYPE what kind of object it is, and NAME the path or address.
In FD, cwd means current working directory, txt means the program text itself, and numbers with r, w, or u are ordinary descriptors open for reading, writing, or both.
What is using this port
sudo lsof -i :8080 # anything on port 8080
sudo lsof -i tcp:443 # TCP only
sudo lsof -i -P -n # every network connection, no name lookups
-P stops port number to service name translation and -n stops DNS lookups. Both make output faster and stop lsof hanging on a slow resolver, and you almost always want them.
For a quick “what is listening,” ss -tlnp is faster. lsof earns its place when you want established connections, the user, and the descriptors together. Our guide to checking open ports covers the lighter tools.
Why the disk is still full
This is the trick that makes lsof worth learning.
You deleted a 40GB log file and df reports no change. That is because deleting a file only removes the directory entry. The inode and its blocks survive until the last file descriptor referring to them is closed, and a running process that had it open still has it open.
sudo lsof +L1
+L1 lists files with a link count below one: files that have been unlinked but are still held open. The NAME column shows the original path with (deleted) appended.
The fix is to make the process close it. Restarting the service works. If it is a log file and the service supports it, sending SIGHUP often makes it reopen its logs, which is exactly what logrotate relies on.
sudo kill -HUP 1234
Why umount says busy
sudo lsof +D /mnt/backup # everything under the mount point
sudo lsof /dev/sdb1 # by device
+D recurses the whole tree, which is thorough and slow on a large mount. +d checks only the directory itself.
The answer is very often a shell whose working directory is inside the mount, including your own in another tab. That shows up as an FD of cwd, and no amount of closing files fixes it because the process is not holding a file, it is standing in the directory.
Filtering by process or user
sudo lsof -p 1234 # one process
sudo lsof -c nginx # every process whose command starts with nginx
sudo lsof -u alice # everything a user has open
sudo lsof -u ^root # everything except root
Combining filters is an OR by default, which surprises people. Use -a to require all of them:
sudo lsof -a -u alice -i # network connections owned by alice
Files under a directory
sudo lsof /var/log/nginx/access.log # who has this specific file
sudo lsof +D /var/log # anything under here
Useful when a file is being written and you want to know by what, particularly when the obvious candidate is not the culprit.
Watching over time
sudo lsof -p 1234 -r 2 # repeat every 2 seconds
A process leaking file descriptors shows up here as a count that only grows. That is a common cause of a service that runs fine for days and then starts failing with “too many open files.”
Check the limit it is running against:
cat /proc/1234/limits | grep "open files"
ls /proc/1234/fd | wc -l # how many it currently has
fuser, for when you just want it gone
fuser -v /mnt/backup # what is using it
sudo fuser -k /mnt/backup # kill those processes
sudo fuser -km /mnt/backup # kill everything using the mount
fuser -k is blunt and effective. Use lsof to understand the situation and fuser to resolve it, and be careful with -k on anything you did not expect.
Two habits worth forming
Use sudo. Without it lsof shows only your own processes and you will conclude nothing is holding a file when something is. This is the single most common reason people give up on the tool.
Use -n -P for anything network related. Name resolution turns a fast command into one that stalls, and the numbers are usually what you wanted anyway.
Frequently Asked Questions
What does lsof actually list?
Open file descriptors across every process on the system. Because Linux represents sockets, pipes, devices, and directories as files, that single list answers questions about network ports, mounted filesystems, and deleted files as well as ordinary open documents.
Why does my disk stay full after deleting a large file?
Deleting a file removes the directory entry, but the space is only reclaimed when the last process holding it open closes it. Run lsof +L1 to list open files with no remaining links, then restart or signal the process that is holding it.
How do I find what is using a port?
lsof -i :8080 shows the process listening on or connected to that port. ss -tlnp is faster for a quick check of listeners, but lsof gives you the full picture including established connections and the file descriptors involved.
Why does umount say the device is busy?
Something has a file open under the mount point, or a process has its working directory inside it. lsof +D /mnt/point lists them. A shell sitting in the directory is the most common culprit and the easiest to miss.
Do I need root to run lsof?
You can run it without root but you will only see your own processes. Anything system-wide needs sudo, and running without it is a common reason people conclude nothing is holding a file when something is.
Is lsof or fuser better?
fuser is terser and better when you just want to kill whatever is holding something, since fuser -k does it directly. lsof gives far more detail and is the better investigative tool. Most people use lsof to understand and fuser to act.