Docker Error Guide: 'device or resource busy' Volume and Mount Removal Failures
Fix Docker 'device or resource busy' on volume rm: find containers still using the volume, clear stale mounts, and release busy bind targets safely.
- #docker
- #troubleshooting
- #errors
- #volumes
Exact Error Message
device or resource busy shows up when you try to remove a volume, remove a container, or unmount a path that something is still holding open:
docker volume rm app_data
Error response from daemon: remove app_data: volume is in use -
[a1b2c3d4e5f6]
docker volume rm app_data
Error response from daemon: unable to remove volume: remove app_data:
rmdir /var/lib/docker/volumes/app_data/_data: device or resource busy
docker rm db
Error response from daemon: container ...: driver "overlay2" failed to
remove root filesystem: unlinkat /var/lib/docker/overlay2/.../merged:
device or resource busy
The volume’s data is intact; Docker simply will not delete a directory or device that the kernel reports as still in use.
What the Error Means
device or resource busy (EBUSY) is a kernel error: an operation tried to remove or unmount something that still has an active reference — an open file handle, a current working directory inside it, or a mount that is nested or leaked into another mount namespace. Docker passes this through verbatim. There are two distinct flavors:
- “volume is in use [container-id]” — Docker’s own bookkeeping knows a container is still attached to the volume. This is a clean refusal; the named container just needs to go away first.
- “rmdir … device or resource busy” / “failed to remove root filesystem” — the kernel itself reports the path busy, usually because a mount leaked into another namespace (a common interaction with systemd’s mount propagation), or a process outside Docker has the directory open.
The first is a Docker-level lock; the second is a host-level mount/handle leak. They look similar but are diagnosed and fixed differently.
Common Causes
- A container still references the volume — running or merely stopped-but-not-removed.
- Anonymous volumes from old containers holding the named volume indirectly.
- Leaked mounts in another namespace. systemd (or another service) inherited Docker’s mount with shared propagation, so the kernel still sees it mounted.
- A host process has a file open under the volume’s
_datadirectory (a backup job, an editor, a shellcd’d into it). - Stale overlay2 mount left by an unclean container stop, keeping
mergedbusy. - NFS/CIFS-backed volume where the remote mount is hung or still active.
How to Reproduce the Error
Create a volume, attach a running container, then try to delete the volume:
docker volume create demo_vol
docker run -d --name holder -v demo_vol:/data alpine sleep 600
docker volume rm demo_vol
Error response from daemon: remove demo_vol: volume is in use -
[<holder-container-id>]
Clean up with docker rm -f holder && docker volume rm demo_vol.
Diagnostic Commands
Find which containers (running or stopped) still reference the volume:
docker ps -a --filter volume=app_data
docker volume inspect app_data
For the kernel-level “rmdir … busy” variant, find what is mounted or open under the path. List mounts referencing the volume:
grep '/var/lib/docker/volumes/app_data' /proc/mounts
mount | grep app_data
Find host processes holding files open under the data dir:
lsof +D /var/lib/docker/volumes/app_data/_data 2>/dev/null
fuser -vm /var/lib/docker/volumes/app_data/_data 2>/dev/null
Read the daemon log for the exact failing path:
journalctl -u docker --since "10 min ago" | grep -i 'busy\|remove\|unlinkat\|rmdir'
Step-by-Step Resolution
Cause: container still attached (clean refusal). Remove the referencing containers first, then the volume:
docker ps -a --filter volume=app_data
docker rm -f <container-id>
docker volume rm app_data
docker volume prune removes all volumes not referenced by any container in one step, once the containers are gone.
Cause: host process holds a file open. Identify the process from lsof/fuser, stop or close it (end the backup job, exit the shell that’s cd’d in), then remove the volume. Do not kill a process blindly — confirm it’s safe first.
Cause: leaked mount in another namespace (rmdir busy). This is the classic systemd interaction. Often the cleanest fix is to restart the Docker daemon, which re-reconciles mounts; if a specific leaked mount remains, unmount it once you’ve confirmed it via /proc/mounts:
grep app_data /proc/mounts
systemctl restart docker
docker volume rm app_data
Cause: stale overlay2 mount on container removal. Stopping the container fully and restarting the daemon clears the leaked merged mount, after which docker rm succeeds. Avoid manually rm -rf-ing under overlay2 while the daemon is running.
Cause: hung NFS/CIFS backend. Restore or unmount the remote share first; an unresponsive remote mount will keep returning EBUSY until the network mount is healthy again.
A worked example. An ops engineer couldn’t delete pg_data even after stopping the database: rmdir ... device or resource busy. docker ps -a --filter volume=pg_data showed no containers, so it wasn’t Docker’s lock. grep pg_data /proc/mounts revealed the volume was still mounted — a leaked mount that systemd had picked up via shared propagation. Restarting the Docker daemon reconciled the mount table, the leaked entry disappeared, and docker volume rm pg_data succeeded. The recurring fix was switching the daemon’s mount propagation handling and ensuring services don’t run with MountFlags=shared that captures Docker mounts.
Prevention and Best Practices
- Always
docker rm(ordocker compose down) containers before removing their volumes; don’t leave stopped containers holding references. - Never
cdinto or run backups directly against/var/lib/docker/volumes/.../_data; mount the data into a throwaway container instead. - Audit services for
MountFlags=shared/propagation settings that can capture Docker’s mounts into other namespaces. - Use
docker volume pruneon a schedule to clear unreferenced volumes cleanly. - For network-backed volumes, monitor the remote share’s health so it never leaves mounts in a hung state.
Related Errors
- Docker Error Guide: ‘invalid mount config for type bind’ — a mount configuration failure at container start rather than removal.
- Docker Error Guide: ‘conflict: unable to remove image’ — another “still in use” removal refusal, for images.
- See more Docker troubleshooting guides.
Frequently Asked Questions
Will I lose data if I force removal? Removing the volume deletes its data. But this error usually blocks removal entirely, so you won’t accidentally delete data — you’ll be told it’s busy first.
Why does docker volume rm say busy when no container is running? Either a stopped (not removed) container still references it, or a host-level mount/handle leak has the directory open. Check docker ps -a --filter volume= and /proc/mounts to tell which.
Can I just umount the path manually? Only after confirming exactly what’s mounted via /proc/mounts. Blind unmounting under /var/lib/docker can corrupt running containers; restarting the daemon is usually safer.
Does docker volume prune bypass this? No. Prune still refuses volumes that are in use; it only removes ones with no container references.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.