Keycloak Connection Refused: Troubleshooting Guide
Last updated: March 2026
“Connection refused” is one of the most common errors when setting up or operating Keycloak. The error means your client (browser, application, or another service) attempted to connect to Keycloak’s port, but nothing was listening there. The causes range from simple port misconfigurations to complex Docker networking issues.
This guide covers every common cause of connection refused errors in Keycloak, organized from the most likely to the least obvious. Each section includes diagnostic commands and a fix.
Quick Diagnostic Checklist
Before diving into specific causes, run through this quick checklist:
# 1. Is Keycloak actually running?
docker ps | grep keycloak
# or
systemctl status keycloak
# 2. What port is Keycloak listening on?
docker logs keycloak 2>&1 | grep "Listening on"
# 3. Can you reach the port locally?
curl -v http://localhost:8080/realms/master
# 4. Is the port mapped correctly (Docker)?
docker port keycloak
# 5. Is something else using the port?
lsof -i :8080
# or on Linux
ss -tlnp | grep 8080
If any of these fail, the corresponding section below will help you fix the issue.
Cause 1: Keycloak Has Not Finished Starting
Keycloak takes 10-30 seconds to start, depending on your hardware and database. If your application tries to connect during startup, it will get a connection refused error.
Diagnosis
Check the container logs for startup status:
docker logs keycloak 2>&1 | tail -20
Look for the line:
Keycloak 26.1.0 on JVM (powered by Quarkus) started in Xs.
If you see messages like Hibernate ORM is disabled or Liquibase: Update command completed, Keycloak is still starting.
Fix
Wait for Keycloak to be ready before connecting. In Docker Compose, use a health check:
services:
keycloak:
image: quay.io/keycloak/keycloak:26.1.0
command: start-dev
environment:
KC_BOOTSTRAP_ADMIN_USERNAME: admin
KC_BOOTSTRAP_ADMIN_PASSWORD: admin
KC_HEALTH_ENABLED: "true"
ports:
- "8080:8080"
healthcheck:
test: ["CMD-SHELL", "exec 3<>/dev/tcp/localhost/9000 && echo -e 'GET /health/ready HTTP/1.1rnHost: localhostrnrn' >&3 && cat <&3 | grep -q '"status":"UP"'"]
interval: 10s
timeout: 5s
retries: 15
start_period: 30s
In a script, poll the health endpoint:
#!/bin/bash
echo "Waiting for Keycloak to start..."
until curl -sf http://localhost:9000/health/ready > /dev/null 2>&1; do
sleep 2
done
echo "Keycloak is ready"
Note: Keycloak’s health endpoint runs on port 9000 by default (separate from the main application port 8080). Make sure KC_HEALTH_ENABLED=true is set.
Cause 2: Wrong Port Configuration
Keycloak 17+ (Quarkus-based) uses different default ports than the older WildFly-based versions.
Keycloak Port Defaults
| Mode | HTTP Port | HTTPS Port | Health Port |
|---|---|---|---|
start-dev |
8080 | 8443 | 9000 |
start (production) |
8080 | 8443 | 9000 |
Diagnosis
Check which port Keycloak is actually listening on:
# Check container logs for the listening port
docker logs keycloak 2>&1 | grep -i "listening"
# Check port mappings
docker port keycloak
Fix
Make sure your Docker port mapping matches:
services:
keycloak:
ports:
- "8080:8080" # HTTP
- "8443:8443" # HTTPS (if configured)
If you have changed the port via environment variable:
environment:
KC_HTTP_PORT: 9090
ports:
- "9090:9090" # Must match KC_HTTP_PORT
Cause 3: Docker Network Isolation
This is the most common cause when one Docker container cannot reach Keycloak running in another container.
Diagnosis
If your application runs in Docker and tries to connect to localhost:8080, it will fail because localhost inside a container refers to the container itself, not the Docker host.
# From inside your application container
docker exec -it my-app curl http://localhost:8080/realms/master
# This will fail with "Connection refused"
Fix
Put both containers on the same Docker network and use the service name as the hostname:
services:
keycloak:
image: quay.io/keycloak/keycloak:26.1.0
command: start-dev
environment:
KC_BOOTSTRAP_ADMIN_USERNAME: admin
KC_BOOTSTRAP_ADMIN_PASSWORD: admin
networks:
- app-network
my-app:
image: my-app:latest
environment:
# Use the service name, not localhost
KEYCLOAK_URL: http://keycloak:8080
depends_on:
keycloak:
condition: service_healthy
networks:
- app-network
networks:
app-network:
driver: bridge
From the my-app container, Keycloak is reachable at http://keycloak:8080, not http://localhost:8080.
For a complete Docker Compose setup with Keycloak, use our Docker Compose Generator.
Container-to-Host Communication
If Keycloak runs on the Docker host (not in a container) and your application runs in a container:
# On Docker Desktop (Mac/Windows)
environment:
KEYCLOAK_URL: http://host.docker.internal:8080
# On Linux
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
KEYCLOAK_URL: http://host.docker.internal:8080
Cause 4: Keycloak Crashed During Startup
Keycloak might start and immediately crash, often due to database connectivity issues or misconfiguration.
Diagnosis
# Check if the container is running or has exited
docker ps -a | grep keycloak
# Check exit code
docker inspect keycloak --format='{{.State.ExitCode}}'
# Check full logs for errors
docker logs keycloak 2>&1 | grep -i "error|exception|failed"
Common crash messages:
Failed to obtain JDBC Connection– Database is unreachableUnable to find columnorLiquibaseerrors – Database schema issuesjava.lang.OutOfMemoryError– Insufficient memory
Fix: Database Connection Issues
If Keycloak cannot reach its database:
services:
postgres:
image: postgres:16
environment:
POSTGRES_DB: keycloak
POSTGRES_USER: keycloak
POSTGRES_PASSWORD: keycloak
healthcheck:
test: ["CMD-SHELL", "pg_isready -U keycloak"]
interval: 5s
timeout: 5s
retries: 10
keycloak:
image: quay.io/keycloak/keycloak:26.1.0
command: start-dev
environment:
KC_DB: postgres
KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: keycloak
depends_on:
postgres:
condition: service_healthy
Key points:
- The database hostname must match the Docker service name (
postgres, notlocalhost) - Use
depends_onwith a health check to ensure the database is ready - Verify credentials match between PostgreSQL and Keycloak configuration
Fix: Memory Issues
Keycloak needs at least 512MB of memory, with 1GB or more recommended:
services:
keycloak:
deploy:
resources:
limits:
memory: 1536M
environment:
JAVA_OPTS_KC_HEAP: "-Xms512m -Xmx1024m"
Cause 5: Hostname Configuration Mismatch
Keycloak’s hostname configuration affects which URLs it accepts connections on. A misconfigured hostname can cause redirects to wrong URLs or refuse connections.
Diagnosis
Check the hostname configuration:
docker logs keycloak 2>&1 | grep -i "hostname"
If you see KC_HOSTNAME set to a specific domain but you are trying to access via localhost, that is the problem.
Fix for Development
For local development, use start-dev mode which disables strict hostname validation:
services:
keycloak:
command: start-dev
environment:
KC_HOSTNAME: localhost
Fix for Production
In production mode (start), configure hostname properly:
environment:
KC_HOSTNAME: auth.example.com
KC_HOSTNAME_STRICT: "true"
KC_PROXY_HEADERS: xforwarded
If you are running behind a reverse proxy, see our guide on running Keycloak behind a reverse proxy for detailed proxy configuration.
Cause 6: Firewall or Security Group Rules
On cloud infrastructure, security groups or firewall rules may block the Keycloak port.
Diagnosis
# Test from outside the server
nc -zv your-server-ip 8080
# Check iptables (Linux)
sudo iptables -L -n | grep 8080
# Check firewalld (RHEL/CentOS)
sudo firewall-cmd --list-ports
# Check UFW (Ubuntu)
sudo ufw status
Fix
# UFW
sudo ufw allow 8080/tcp
# firewalld
sudo firewall-cmd --permanent --add-port=8080/tcp
sudo firewall-cmd --reload
# AWS Security Group - via CLI
aws ec2 authorize-security-group-ingress
--group-id sg-xxx
--protocol tcp
--port 8080
--cidr 10.0.0.0/16
Cause 7: Kubernetes-Specific Issues
In Kubernetes, connection refused errors often stem from service configuration or pod readiness.
Diagnosis
# Check pod status
kubectl get pods -l app=keycloak
# Check pod logs
kubectl logs -l app=keycloak --tail=50
# Check service endpoints
kubectl get endpoints keycloak-service
# Port-forward to test directly
kubectl port-forward svc/keycloak-service 8080:8080
Common Issues
Service targetPort mismatch:
# Wrong - targetPort doesn't match Keycloak's port
apiVersion: v1
kind: Service
metadata:
name: keycloak-service
spec:
ports:
- port: 80
targetPort: 80 # Should be 8080
# Correct
spec:
ports:
- port: 80
targetPort: 8080 # Keycloak's actual port
Missing readiness probe:
spec:
containers:
- name: keycloak
readinessProbe:
httpGet:
path: /health/ready
port: 9000
initialDelaySeconds: 30
periodSeconds: 10
Without a readiness probe, the service might route traffic to a pod that is not ready yet. For Kubernetes deployment best practices, see our guide on deploying Keycloak with ArgoCD.
Cause 8: SSL/TLS Configuration
If Keycloak is configured for HTTPS but you are connecting via HTTP (or vice versa), you will get a connection refused error.
Diagnosis
# Try both HTTP and HTTPS
curl -v http://localhost:8080/realms/master
curl -vk https://localhost:8443/realms/master
Fix
In development mode, Keycloak listens on HTTP by default. In production mode, it expects HTTPS:
# For development - HTTP only
environment:
KC_HTTP_ENABLED: "true"
KC_HOSTNAME_STRICT_HTTPS: "false"
# For production with TLS termination at the proxy
environment:
KC_HTTP_ENABLED: "true"
KC_PROXY_HEADERS: xforwarded
KC_HOSTNAME: auth.example.com
For SSL certificate issues, see our Keycloak SSL certificate error fix guide.
Cause 9: Keycloak Version URL Changes
Keycloak 17+ changed its URL structure. If you upgraded from an older version, your URLs might be wrong.
Old vs New URL Patterns
| Resource | Keycloak 16 and earlier | Keycloak 17+ |
|---|---|---|
| Admin console | /auth/admin/ |
/admin/ |
| Realm endpoint | /auth/realms/{realm} |
/realms/{realm} |
| Token endpoint | /auth/realms/{realm}/protocol/openid-connect/token |
/realms/{realm}/protocol/openid-connect/token |
| OIDC discovery | /auth/realms/{realm}/.well-known/openid-configuration |
/realms/{realm}/.well-known/openid-configuration |
Diagnosis
# Try both URL patterns
curl -sf http://localhost:8080/realms/master > /dev/null && echo "New URL pattern works"
curl -sf http://localhost:8080/auth/realms/master > /dev/null && echo "Old URL pattern works"
Fix
Update your application configuration to use the new URL pattern (without /auth/). If you cannot update all clients immediately, Keycloak supports a compatibility mode:
environment:
KC_HTTP_RELATIVE_PATH: /auth
This restores the /auth/ prefix. However, it is recommended to migrate to the new URL pattern. For more details on URL changes across versions, see our Keycloak realm not found troubleshooting guide.
Cause 10: CORS Blocking Requests
If your browser shows a connection error but curl works fine, CORS (Cross-Origin Resource Sharing) might be the issue. The browser blocks the request before it reaches Keycloak, which can appear similar to a connection refused error.
Diagnosis
Check the browser’s developer console for CORS errors:
Access to XMLHttpRequest at 'http://localhost:8080/...' from origin 'http://localhost:3000'
has been blocked by CORS policy
Fix
Configure the client’s Web Origins in Keycloak:
- Open the Keycloak admin console
- Navigate to your realm > Clients > your client
- Add your application’s origin to “Web Origins” (e.g.,
http://localhost:3000)
Or set Web Origins to + to automatically allow all redirect URIs as origins.
For a deep dive into CORS configuration, see our guide on configuring CORS with Keycloak OIDC clients.
Systematic Debugging Approach
When none of the above causes are obvious, use this systematic approach:
# Step 1: Verify Keycloak is running and check logs
docker ps -a | grep keycloak
docker logs keycloak --tail 100
# Step 2: Test connectivity from the same host
curl -v http://localhost:8080/realms/master
# Step 3: Test from inside the Docker network
docker run --rm --network $(docker network ls -q -f name=myapp)
curlimages/curl curl -v http://keycloak:8080/realms/master
# Step 4: Check DNS resolution inside Docker
docker run --rm --network $(docker network ls -q -f name=myapp)
busybox nslookup keycloak
# Step 5: Check port availability
docker run --rm --network $(docker network ls -q -f name=myapp)
busybox nc -zv keycloak 8080
# Step 6: Verify the token endpoint specifically
curl -s http://localhost:8080/realms/master/.well-known/openid-configuration | jq '.token_endpoint'
You can analyze tokens returned from a working Keycloak instance using our JWT Token Analyzer to verify the token structure is correct.
Preventing Connection Issues
To avoid connection refused errors in the first place:
- Always use health checks in Docker Compose and Kubernetes. Never rely on
depends_onalone. - Implement retry logic in your application for initial Keycloak connections.
- Use Skycloak’s managed hosting to eliminate infrastructure-level connection issues entirely. Skycloak handles networking, SSL, health monitoring, and high availability.
- Monitor Keycloak’s health endpoint with your observability stack. See our Keycloak insights for built-in monitoring.
- Document your networking setup. Knowing which ports, networks, and hostname configurations are in use prevents debugging sessions later.
Further Reading
- Keycloak Server Administration: Networking
- How to Run Keycloak Behind a Reverse Proxy
- Keycloak SSL Certificate Error Fix
- Keycloak 403 Forbidden Troubleshooting
- Keycloak Realm Not Found Troubleshooting
- 8 Default Configurations to Adjust on Your Keycloak Cluster
Tired of debugging Keycloak infrastructure issues? Skycloak provides managed Keycloak hosting with built-in monitoring, automatic failover, and guaranteed SLA. See pricing to get started.
Ready to simplify your authentication?
Deploy production-ready Keycloak in minutes. Unlimited users, flat pricing, no SSO tax.