How to fix Container did not respond to SIGTERM within timeout in Docker

DockerINTERMEDIATEMEDIUMUpdated Dec 6, 2025ยท 284 views

This error occurs when Docker sends a SIGTERM signal to gracefully stop a container, but the process inside doesn't respond before the timeout expires. Docker then forcibly kills the container with SIGKILL. The fix involves proper signal handling, using exec form in Dockerfiles, or adding an init process.

Quick fix

Fixes Container did not respond to SIGTERM within timeout

# BAD - shell form, wraps in /bin/sh -c
CMD /app/server
ENTRYPOINT /docker-entrypoint.sh
  1. Use exec form for CMD and ENTRYPOINT
  2. Use exec in shell entrypoint scripts
  3. Add an init process with --init or tini
  4. Implement SIGTERM handlers in your application
docker โ€” error
# BAD - shell form, wraps in /bin/sh -c
CMD /app/server
ENTRYPOINT /docker-entrypoint.sh
Container did not respond to SIGTERM within timeout

What this error means

When you run `docker stop`, Docker sends a SIGTERM signal to the main process (PID 1) inside the container, giving it a chance to gracefully shut down. If the process doesn't exit within the timeout period (default: 10 seconds), Docker sends SIGKILL to forcibly terminate the container. The "Container did not respond to SIGTERM within timeout" error indicates that your application didn't handle the SIGTERM signal properly. This is a common issue because PID 1 processes in containers have special behavior: they won't receive signals unless they explicitly install signal handlers for them. This problem often occurs when: 1. Your application runs via a shell wrapper (e.g., `CMD /app/start.sh`) where the shell intercepts signals 2. Your process manager or runtime doesn't forward signals to child processes 3. Your application doesn't implement SIGTERM handlers 4. The application's graceful shutdown takes longer than the configured timeout

Typical symptoms

  • docker stop takes exactly 10 seconds (or the configured timeout) before completing
  • Container exits with code 137 (128 + 9, where 9 is SIGKILL)
  • Application doesn't run cleanup tasks before shutdown (database connections not closed, files not flushed)
  • Kubernetes pods take a long time to terminate
  • CI/CD pipelines are slow due to container shutdown delays
  • docker-compose down hangs for each service
  • Data corruption or incomplete transactions after container stops

Common causes

  1. Using shell form (CMD /app/start.sh) instead of exec form (CMD ["/app/start.sh"]) in Dockerfile
  2. Application running as PID 1 without installing SIGTERM signal handlers
  3. Entrypoint shell script not using exec to replace itself with the main process
  4. Process managers like npm, supervisord, or pm2 not forwarding signals to child processes
  5. Application's graceful shutdown takes longer than the configured timeout
  6. Running multiple processes without proper init system to manage signals
  7. Bash scripts using sleep or tail without proper trap handlers

How to fix "Container did not respond to SIGTERM within timeout"

1Use exec form for CMD and ENTRYPOINT

The most common cause is using shell form in your Dockerfile, which wraps your command in /bin/sh -c. The shell doesn't forward signals to child processes.

Instead of shell form:

dockerfile
# BAD - shell form, wraps in /bin/sh -c
CMD /app/server
ENTRYPOINT /docker-entrypoint.sh

Use exec form (JSON array):

dockerfile
# GOOD - exec form, process runs directly as PID 1
CMD ["/app/server"]
ENTRYPOINT ["/docker-entrypoint.sh"]

Verify your process is PID 1:

bash
docker exec <container> ps aux

Your main application should be PID 1, not /bin/sh.

2Use exec in shell entrypoint scripts

If you need a shell script as entrypoint (for environment setup, etc.), use exec to replace the shell with your application:

bash
#!/bin/bash
# docker-entrypoint.sh

# Do setup work
echo "Setting up environment..."
export DATABASE_URL="postgres://..."

# IMPORTANT: Use exec to replace shell with main process
# This ensures your app receives signals directly
exec node /app/server.js

Without exec, the shell remains as PID 1 and your app runs as a child process. When Docker sends SIGTERM to PID 1 (the shell), it's not forwarded to your application.

Before (shell remains PID 1):

bash
PID 1: /bin/bash /docker-entrypoint.sh
PID 8: node /app/server.js  <- doesn't receive SIGTERM

After exec (app is PID 1):

bash
PID 1: node /app/server.js  <- receives SIGTERM directly
3Add an init process with --init or tini

Use Docker's built-in init process to properly handle signals and reap zombie processes:

Using Docker's --init flag:

bash
docker run --init myimage

In Docker Compose:

yaml
services:
  myapp:
    image: myimage
    init: true

Or install tini in your Dockerfile:

dockerfile
# For Alpine
RUN apk add --no-cache tini
ENTRYPOINT ["/sbin/tini", "--"]
CMD ["/app/server"]

# For Debian/Ubuntu
RUN apt-get update && apt-get install -y tini
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["/app/server"]

Tini runs as PID 1 and:
- Forwards signals to your application
- Reaps zombie processes
- Handles the special PID 1 signal semantics

4Implement SIGTERM handlers in your application

If your application runs as PID 1, it must explicitly handle SIGTERM:

Node.js:

javascript
process.on('SIGTERM', () => {
  console.log('Received SIGTERM, shutting down gracefully...');
  server.close(() => {
    console.log('Server closed');
    process.exit(0);
  });

  // Force exit after timeout if graceful shutdown fails
  setTimeout(() => {
    console.error('Graceful shutdown timed out, forcing exit');
    process.exit(1);
  }, 8000);
});

Python:

python
import signal
import sys

def handle_sigterm(signum, frame):
    print('Received SIGTERM, shutting down...')
    # Cleanup code here
    sys.exit(0)

signal.signal(signal.SIGTERM, handle_sigterm)

Go:

go
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGTERM, syscall.SIGINT)

go func() {
    <-sigs
    log.Println("Received shutdown signal")
    // Cleanup and shutdown
    os.Exit(0)
}()

Java:

java
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
    System.out.println("Shutting down gracefully...");
    // Cleanup code
}));
5Increase the stop timeout

If your application legitimately needs more time to shut down gracefully, increase the timeout:

docker stop command:

bash
docker stop --time=30 <container>  # Wait 30 seconds
docker stop -t 60 <container>       # Wait 60 seconds
docker stop -t -1 <container>       # Wait indefinitely

Docker Compose:

yaml
services:
  myapp:
    image: myimage
    stop_grace_period: 30s

Kubernetes:

yaml
spec:
  terminationGracePeriodSeconds: 30

Note: This should be a last resort. If your app needs more than 10 seconds to shut down, consider:
- Pre-draining connections before stop
- Reducing cleanup work
- Running cleanup as a separate process

6Fix signal handling in shell scripts

If you must use a shell script that doesn't exec, add proper signal trapping:

bash
#!/bin/bash

cleanup() {
    echo "Caught signal, cleaning up..."
    kill -TERM "$child_pid" 2>/dev/null
    wait "$child_pid"
    exit 0
}

trap cleanup SIGTERM SIGINT

# Run your app in background
/app/server &
child_pid=$!

# Wait for it (this allows trap to work)
wait "$child_pid"

Important: Using sleep or tail -f blocks signal processing. Always use wait to allow traps to execute:

bash
# BAD - blocks signals
/app/server &
tail -f /dev/null

# GOOD - allows signal handling
/app/server &
wait $!
7Configure the correct stop signal

Some applications expect a different signal than SIGTERM. For example, nginx and PHP-FPM use SIGQUIT for graceful shutdown.

In Dockerfile:

dockerfile
FROM nginx:alpine
STOPSIGNAL SIGQUIT

When running container:

bash
docker run --stop-signal=SIGQUIT nginx

In Docker Compose:

yaml
services:
  nginx:
    image: nginx
    stop_signal: SIGQUIT

Common stop signals by application:
- nginx: SIGQUIT
- PHP-FPM: SIGQUIT
- Apache: SIGWINCH (graceful) or SIGTERM
- Most applications: SIGTERM (default)

Advanced notes

PID 1 Signal Semantics in Linux:
In Linux, PID 1 (the init process) has special signal handling. It will only receive signals if it has explicitly installed a handler for them. This is a kernel-level protection to prevent accidentally killing the init process and bringing down the system.

When a process runs as PID 1 in a container namespace, this same behavior applies. That's why signals seem to "bounce off" processes that don't handle them.

Debugging signal issues:

bash
# Check which process is PID 1
docker exec <container> cat /proc/1/comm

# Trace signals being sent
docker exec <container> strace -p 1 -e trace=signal

# Check if tini is being used
docker exec <container> ps aux | head -5

Don't use npm start for production:

dockerfile
# BAD - npm doesn't forward signals
CMD ["npm", "start"]

# GOOD - node receives signals directly
CMD ["node", "server.js"]

npm, yarn, and other package managers don't properly forward signals. Always invoke your runtime directly in production containers.

Kubernetes preStop hooks:
For critical cleanup that must complete, use a preStop hook:

yaml
lifecycle:
  preStop:
    exec:
      command: ["/bin/sh", "-c", "sleep 5 && /app/drain-connections.sh"]

Testing graceful shutdown:

bash
# Start container
docker run -d --name test myimage

# Send SIGTERM and observe
docker stop test

# Check exit code (should be 0 for graceful, 137 for forced)
docker inspect test --format='{{.State.ExitCode}}'

Avoiding dumb-init vs tini debate:
Both dumb-init and tini solve the same problem. tini is slightly smaller and is built into Docker (--init flag uses tini). Either works well.

Frequently asked questions

What does "Container did not respond to SIGTERM within timeout" mean?
When you run docker stop, Docker sends a SIGTERM signal to the main process (PID 1) inside the container, giving it a chance to gracefully shut down. If the process doesn't exit within the timeout period (default: 10 seconds), Docker sends SIGKILL to forcibly terminate the container. The "Container did not respond to SIGTERM within timeout" error indicates that your application didn't handle the SIGTERM signal properly.
How do I fix "Container did not respond to SIGTERM within timeout"?
This error occurs when Docker sends a SIGTERM signal to gracefully stop a container, but the process inside doesn't respond before the timeout expires. Docker then forcibly kills the container with SIGKILL. The fix involves proper signal handling, using exec form in Dockerfiles, or adding an init process.
What causes "Container did not respond to SIGTERM within timeout"?
Using shell form (CMD /app/start.sh) instead of exec form (CMD ["/app/start.sh"]) in Dockerfile Application running as PID 1 without installing SIGTERM signal handlers Entrypoint shell script not using exec to replace itself with the main process
Is the "Container did not respond to SIGTERM within timeout" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading