Skip to content
DevOps AI ToolKit
Newsletter
All guides
Docker with AI By James Joyner IV · · 9 min read

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:

  1. “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.
  2. “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 _data directory (a backup job, an editor, a shell cd’d into it).
  • Stale overlay2 mount left by an unclean container stop, keeping merged busy.
  • 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 (or docker compose down) containers before removing their volumes; don’t leave stopped containers holding references.
  • Never cd into 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 prune on 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.

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.

Free download · 368-page PDF

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.