The 'secret is in use by the following services' error occurs when you attempt to delete a Docker Swarm secret that is still referenced by one or more services. Remove the secret from the services first using `docker service update --secret-rm`, or delete the services entirely before removing the secret.
The "secret is in use by the following services" error appears when you try to delete a Docker Swarm secret using `docker secret rm` while active services still have access to that secret. In Docker Swarm, secrets are encrypted pieces of sensitive data (passwords, API keys, certificates) that are made available only to services that explicitly request them. When you grant a service access to a secret, Docker creates a dependency link between them. This link prevents accidental deletion of secrets that services rely on. Unlike Docker volumes, you cannot force-delete a secret that's in use. Docker requires you to explicitly break the dependency by either removing the secret from the service configuration or deleting the service entirely. This is a deliberate safety mechanism to prevent services from suddenly losing access to credentials they need to function. The error message helpfully lists which services are using the secret, making it straightforward to identify what needs to be updated.
First, identify which services are referencing the secret. The error message usually tells you, but you can also query Docker:
# List all services and their secrets
docker service ls --format "{{.Name}}" | while read svc; do
secrets=$(docker service inspect $svc --format '{{range .Spec.TaskTemplate.ContainerSpec.Secrets}}{{.SecretName}} {{end}}')
if [ -n "$secrets" ]; then
echo "$svc: $secrets"
fi
done
# Inspect a specific service to see its secrets
docker service inspect <service_name> --format '{{json .Spec.TaskTemplate.ContainerSpec.Secrets}}' | jq
# List all secrets with their IDs
docker secret lsNote which services are using the secret you want to delete.
If you want to keep the service running but remove its access to the secret, use docker service update:
# Remove a secret from a single service
docker service update --secret-rm <secret_name> <service_name>
# Example: Remove database password from api service
docker service update --secret-rm db_password api_service
# Remove secret from multiple services
for svc in service1 service2 service3; do
docker service update --secret-rm <secret_name> $svc
doneImportant: This will cause a rolling update of the service. Containers will be recreated without access to the secret. Ensure your application can handle the secret's absence or has been reconfigured to use an alternative.
After removing the secret from all services, delete it:
docker secret rm <secret_name>If you no longer need the services, remove them entirely:
# Remove a specific service
docker service rm <service_name>
# Remove multiple services
docker service rm service1 service2 service3Once all services using the secret are removed, you can delete the secret:
docker secret rm <secret_name>Tip: If you deployed with Docker Compose/Stack, use the stack command for cleaner removal:
# Remove entire stack (services, networks, but NOT secrets by default)
docker stack rm <stack_name>
# After stack is removed, delete the secret
docker secret rm <secret_name>If you need to replace a secret (rotation), you can add the new secret first, then remove the old one:
# Create new secret with different name
echo "new_password_value" | docker secret create db_password_v2 -
# Update service to use new secret (optionally with target to keep same filename)
docker service update \
--secret-rm db_password \
--secret-add source=db_password_v2,target=db_password \
<service_name>
# After service updates successfully, remove old secret
docker secret rm db_passwordUsing the target option means your application still reads the secret from /run/secrets/db_password even though the actual secret is named db_password_v2. This allows seamless rotation without application changes.
If you deployed services using docker stack deploy, note that docker stack rm does NOT automatically remove secrets created by the stack.
# Remove the stack
docker stack rm mystack
# Wait for services to be fully removed
sleep 10
# Verify no services remain
docker service ls
# Now remove the secrets manually
docker secret rm secret1 secret2 secret3
# Or remove all unused secrets (be careful!)
docker secret ls --format "{{.Name}}" | while read secret; do
docker secret rm $secret 2>/dev/null && echo "Removed: $secret"
doneWarning: The last command removes ALL secrets not currently in use. Only use this if you're certain you want to clean everything.
### How Docker Swarm Secrets Work
Docker Swarm secrets are stored encrypted in the Raft log on manager nodes. When a service needs a secret:
1. The manager decrypts the secret
2. Sends it over a mutually-authenticated TLS connection to the worker node
3. The secret is mounted as a tmpfs filesystem at /run/secrets/<secret_name> inside the container
4. The secret is never written to disk on worker nodes
This is why secrets require Swarm mode - the encryption and distribution infrastructure only exists in Swarm.
### Secrets vs Environment Variables
| Aspect | Secrets | Environment Variables |
|--------|---------|----------------------|
| Storage | Encrypted in Raft | Plain text in container config |
| Access | File at /run/secrets/ | $VAR or getenv() |
| Visibility | Not shown in docker inspect | Visible in docker inspect |
| Updates | Requires service update | Requires service update |
Always prefer secrets for sensitive data.
### External vs Stack-Created Secrets
Secrets can be "external" (created before stack deploy) or created by the stack:
# docker-compose.yml
secrets:
db_password:
external: true # Must exist before deploy
api_key:
file: ./api_key.txt # Created during deployExternal secrets persist after docker stack rm, while stack-created secrets are typically removed with the stack (behavior varies by Docker version).
### Checking Secret Usage Across All Services
# Script to list all secrets and which services use them
for secret in $(docker secret ls --format "{{.Name}}"); do
echo "Secret: $secret"
for svc in $(docker service ls --format "{{.Name}}"); do
if docker service inspect $svc --format '{{range .Spec.TaskTemplate.ContainerSpec.Secrets}}{{.SecretName}}{{end}}' | grep -q "$secret"; then
echo " - Used by: $svc"
fi
done
echo ""
done### Secrets in CI/CD Pipelines
When automating deployments, handle secret dependencies carefully:
# Safe secret rotation in CI/CD
NEW_SECRET_NAME="db_password_$(date +%Y%m%d)"
# Create new secret
echo "$DB_PASSWORD" | docker secret create $NEW_SECRET_NAME -
# Update service atomically
docker service update \
--secret-rm db_password_old \
--secret-add source=$NEW_SECRET_NAME,target=db_password \
myservice
# Clean up old secret only after service is healthy
docker secret rm db_password_old### Troubleshooting Secret Access Issues
If a service can't access a secret:
# Check if secret exists
docker secret ls | grep <secret_name>
# Verify service has secret configured
docker service inspect <service_name> --format '{{json .Spec.TaskTemplate.ContainerSpec.Secrets}}'
# Check container can read the secret (exec into running container)
docker exec -it $(docker ps -q -f name=<service_name>) cat /run/secrets/<secret_name>If the secret file doesn't exist inside the container, the service configuration may have been updated without including the secret.
dockerfile parse error line 5: unknown instruction: RRUN
How to fix 'unknown instruction' Dockerfile parse error in Docker
Error response from daemon: manifest for nginx:nonexistent not found: manifest unknown: manifest unknown
How to fix 'manifest for image:tag not found' in Docker
Error response from daemon: invalid reference format: repository name must be lowercase
How to fix 'repository name must be lowercase' in Docker
Error response from daemon: No such image
How to fix 'No such image' in Docker
Error response from daemon: Container is not running
How to fix 'Container is not running' when using docker exec