1. Introduction

You've set up a Jenkins pipeline to build Docker images, and it fails immediately with an error like this:

Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Post "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/build": dial unix /var/run/docker.sock: connect: permission denied

This is one of the most common CI/CD setup problems on Jenkins, and it has several valid fixes depending on how your Jenkins is deployed. After fixing Docker access, if your containerised application starts crashing, see Fix Kubernetes CrashLoopBackOff. The wrong fix can introduce a real security risk — so this guide covers not just how to make it work, but which approach is appropriate for your setup.

2. What This Error Means

Docker communicates with its daemon through a Unix socket: /var/run/docker.sock. By default, that socket is owned by root and the docker group, with permissions that look like this:

ls -la /var/run/docker.sock
      # srw-rw---- 1 root docker 0 Apr 21 09:14 /var/run/docker.sock

The jenkins user running your pipeline doesn't belong to the docker group, so it can't read or write to the socket. The Docker CLI can't talk to the daemon, and every Docker command fails immediately.

There are three distinct deployment scenarios where this error appears, and each has a different correct fix:

3. Common Causes

4. Step-by-Step Fix

Step 1: Identify your Jenkins deployment type

Before applying any fix, confirm how Jenkins is running. This determines everything:

# Check if Jenkins is running as a system service (bare metal / VM install) systemctl status jenkins
      # Check if Jenkins is running as a container docker ps | grep jenkins
      # Check the user Jenkins pipelines run as
      # Add this shell step to a test pipeline: sh 'whoami && id'

Step 2 (Bare metal / VM): Add the jenkins user to the docker group

This is the correct fix for Jenkins installed directly on a Linux host. The jenkins user needs to be a member of the docker group to access the socket:

# Add jenkins user to the docker group sudo usermod -aG docker jenkins
      # Verify the change id jenkins
      # uid=115(jenkins) gid=121(jenkins) groups=121(jenkins),999(docker)
      # IMPORTANT: restart Jenkins to apply the new group membership
      # The change does NOT take effect until Jenkins is restarted sudo systemctl restart jenkins

Verify it worked by running a test pipeline with:

sh 'docker info'

Step 3 (Containerised Jenkins): Mount and configure the Docker socket

If Jenkins itself is running in a Docker container, the standard approach is to bind-mount the host's Docker socket into the container. This lets the Jenkins container use the host's Docker daemon:

# docker run example with socket mounted docker run -d \   --name jenkins \   -p 8080:8080 \   -v /var/run/docker.sock:/var/run/docker.sock \   -v jenkins_home:/var/jenkins_home \   jenkins/jenkins:lts
      # After starting the container, install Docker CLI inside it
      # and add the jenkins user to the docker group: docker exec -it -u root jenkins bash apt-get update && apt-get install -y docker.io
      # Get the GID of the docker group on the HOST
      # (run this on the host, not inside the container) getent group docker | cut -d: -f3
      # e.g. 999
      # Inside the container: add jenkins user to a group with that GID groupmod -g 999 docker   # or: groupadd -g 999 docker usermod -aG docker jenkins

If you manage this with Docker Compose, the cleaner approach is to set it in your compose file:

# docker-compose.yml services:   jenkins:     image: jenkins/jenkins:lts     user: root   # or a specific UID:GID     volumes:       - /var/run/docker.sock:/var/run/docker.sock       - jenkins_home:/var/jenkins_home     ports:       - "8080:8080"
      # Running as root avoids the GID problem but has broader security implications.
      # See the security section below for the right tradeoff.

Step 4 (Kubernetes agents): Choose the right approach

Kubernetes clusters typically run containerd or CRI-O as the container runtime — there is no Docker daemon on the node for Jenkins agents to connect to. You have three realistic options:

Option A: Docker-in-Docker (DinD) sidecar

# Jenkinsfile — Kubernetes agent with DinD sidecar pipeline {   agent {     kubernetes {       yaml '''        
      apiVersion: v1        
      kind: Pod         spec:           containers:           - name: jnlp             image: jenkins/inbound-agent:latest           - name: docker             image: docker:24-dind             securityContext:               privileged: true             env:             - name: DOCKER_TLS_CERTDIR               value: ""             volumeMounts:             - name: docker-storage               mountPath: /var/lib/docker           volumes:           - name: docker-storage             emptyDir: {}       '''     }   }   stages {     stage('Build') {       steps {         container('docker') {           sh 'docker build -t myapp:latest .'         }       }     }   } }

Option B: Kaniko (no Docker daemon required)

# Jenkinsfile — Kaniko build in Kubernetes pipeline {   agent {     kubernetes {       yaml '''        
      apiVersion: v1        
      kind: Pod         spec:           containers:           - name: kaniko             image: gcr.io/kaniko-project/executor:latest             command: ["/busybox/cat"]             tty: true       '''     }   }   stages {     stage('Build & Push') {       steps {         container('kaniko') {           sh '''             /kaniko/executor \               --context=. \               --dockerfile=Dockerfile \               --destination=myregistry/myapp:${BUILD_NUMBER}           '''         }       }     }   } }

5. Verification Steps

After applying your fix, run the following verification checks before testing a full pipeline build:

Bare metal / VM

# Confirm jenkins is in the docker group id jenkins
      # Expected: groups=...,999(docker)
      # Test Docker access as the jenkins user sudo -u jenkins docker info sudo -u jenkins docker ps
      # If the above works, run a test pipeline stage: sh 'docker version'

Containerised Jenkins

# From inside the Jenkins container, verify socket access docker exec -it -u jenkins jenkins docker info
      # Confirm the socket is mounted and its GID matches the host docker exec -it jenkins ls -la /var/run/docker.sock
      # srw-rw---- 1 root 999 0 Apr 21 09:14 /var/run/docker.sock
      # GID 999 should match the host's docker group GID getent group docker    # run this on the host

Kubernetes agents

# Create a minimal test pipeline that runs docker info
      # in the docker/DinD container sidecar: container('docker') {   sh 'docker info'   sh 'docker version' }
      # For Kaniko, verify the executor runs without errors: container('kaniko') {   sh '/kaniko/executor --help' }

6. Approaches at a Glance

Here's a comparison of every fix approach so you can choose the right one for your environment:

ApproachHow it worksBest forTradeoff
Add jenkins to docker groupJenkins user gets read/write access to /var/run/docker.sockSimple single-node Jenkins setupsGrants root-equivalent host access to Jenkins jobs
Docker socket bind mountMount host socket into Jenkins agent containerContainerised Jenkins agentsSame security concern — socket access = host root
Docker-in-Docker (DinD)Run a separate Docker daemon in a privileged containerKubernetes-based Jenkins agents, CI isolationPrivileged container required; slower builds
Rootless DockerDocker daemon runs as non-root userSecurity-conscious environmentsMore complex setup; some features limited
Kaniko / BuildahBuild images without a Docker daemon at allKubernetes-native CI, high-security environmentsDifferent syntax; not a drop-in replacement

For most teams running Jenkins on a VM or bare metal, adding the jenkins user to the docker group is the pragmatic choice. For Kubernetes-based CI, Kaniko is the most robust long-term option.

7. Security Considerations

Practical mitigations if you're using socket mounting:

8. Common Mistakes

9. Prevention Tips

10. Summary

The Docker permission denied error on Jenkins always comes down to the same root cause: the Jenkins process can't access /var/run/docker.sock. Once your Docker builds are working, you may encounter ECR authentication errors when pushing images to AWS ECR. The fix depends entirely on your deployment setup:

SetupRecommended fix
Jenkins on bare metal / VMusermod -aG docker jenkins, then restart the Jenkins service
Jenkins in a Docker containerMount the socket, match the host docker GID inside the container
Kubernetes agents (Docker cluster)DinD sidecar with privileged: true
Kubernetes agents (containerd/CRI-O)Use Kaniko or Buildah — no Docker daemon is available

If you remember nothing else: usermod -aG docker jenkins works on bare metal, but you must restart Jenkins after. And if you're on Kubernetes, check whether Docker is even available on the node before reaching for DinD.