1. Introduction

When kubectl returns connection refused, Unable to connect to the server, or no such host, the control plane is either unreachable or your client isn't configured correctly to reach it. For engineers managing production clusters, this can be a critical situation: you've lost the ability to diagnose or remediate anything in the cluster until the connection is restored.

The problem is either in your client (kubeconfig, VPN, credentials) or in the API server itself (crashed, OOMKilled, network partition). Separating client issues from server issues is the first step.

2. What the Error Actually Means

The Kubernetes API server is a REST API that kubectl (and all internal components) communicate with over HTTPS. "Connection refused" means the TCP connection was actively rejected — nothing is listening at that address and port. "Connection timed out" means the packet is being dropped — a firewall or routing issue. "TLS handshake failed" means connectivity works but the certificate is wrong or expired.

3. Common Causes

4. Step-by-Step Diagnosis and Fix

Step 1: Read the exact error message

# Run kubectl with verbose output to see full connection details
kubectl cluster-info --v=8 2>&1 | head -30

# Common patterns and what they mean:
# "connection refused" = nothing listening at that IP:port
# "no such host" = DNS can't resolve the API server hostname
# "certificate signed by unknown authority" = cert trust issue
# "TLS handshake timeout" = connectivity but TLS failing
# "context deadline exceeded" = timeout (firewall dropping packets)
# "You must be logged in to the server (Unauthorized)" = auth issue, not connectivity

Step 2: Check and fix kubeconfig

# View current context
kubectl config current-context
kubectl config view

# Check the server endpoint
kubectl config view -o jsonpath='{.clusters[].cluster.server}'
# Should return: https://<api-server-ip-or-hostname>:6443

# List all contexts
kubectl config get-contexts

# Switch to correct context
kubectl config use-context <correct-context>

# For EKS: regenerate kubeconfig
aws eks update-kubeconfig --region <region> --name <cluster-name>

Step 3: Test raw connectivity

# Extract the API server URL from kubeconfig
API_SERVER=$(kubectl config view -o jsonpath='{.clusters[].cluster.server}')

# Test TCP connectivity
curl -k $API_SERVER/healthz
# Expected: "ok"
# If curl can't connect, it's a network issue

# Test DNS resolution
nslookup <api-server-hostname>

# Test with specific port
nc -zv <api-server-ip> 6443

Step 4: Check API server pod health (self-managed clusters)

# On the control plane node via SSH:
# Check API server static pod
ls /etc/kubernetes/manifests/kube-apiserver.yaml

# Check if the container is running
crictl ps | grep kube-apiserver
# or: docker ps | grep kube-apiserver

# Check logs
crictl logs <apiserver-container-id>
# or: journalctl -u kubelet | grep apiserver

# Restart by touching the static pod manifest (kubelet will recreate)
touch /etc/kubernetes/manifests/kube-apiserver.yaml

Step 5: Check TLS certificates

# Check certificate expiry dates on control plane node
# kubeadm-managed certificates:
kubeadm certs check-expiration

# Manual check:
openssl x509 -noout -dates -in /etc/kubernetes/pki/apiserver.crt

# If expired, renew with kubeadm:
kubeadm certs renew all

# After renewing: restart API server
systemctl restart kubelet

Step 6: Fix EKS private endpoint access

# Check EKS endpoint access settings
aws eks describe-cluster --name <cluster-name>   --query 'cluster.resourcesVpcConfig.{Private:endpointPrivateAccess,Public:endpointPublicAccess}'

# If Public=false and you're connecting from outside the VPC, you need:
# 1. VPN connection to the VPC
# 2. Or enable public access temporarily:
aws eks update-cluster-config --region <region> --name <cluster-name>   --resources-vpc-config endpointPublicAccess=true

5. Verification Steps

# Basic connectivity check
kubectl cluster-info
# Expected: "Kubernetes control plane is running at https://..."

# Run a basic command
kubectl get nodes
# Should return node list

# Check API server health directly
curl -k $(kubectl config view -o jsonpath='{.clusters[].cluster.server}')/healthz
# Expected: "ok"

6. Common Mistakes

7. Prevention Tips

8. FAQ

kubectl works from my laptop but not from CI/CD. Why?

The CI/CD environment has different network access and a different kubeconfig. Common causes: the CI runner doesn't have VPN access to the cluster's VPC, the kubeconfig in CI has an expired token, or the ServiceAccount used by CI doesn't have the right RBAC permissions. Check the exact error — "Unauthorized" means auth failed, not connectivity; "connection refused" means network.

The API server is responding but kubectl returns "Forbidden". Is that a connection issue?

No — "Forbidden" (403) means connectivity works fine but the requesting identity doesn't have permission for that operation. That's an RBAC issue, not an API server connection issue. Check kubectl auth can-i <verb> <resource> to understand what the current identity is allowed to do.

9. Summary

ErrorCauseFix
connection refusedWrong endpoint or API server downCheck kubeconfig server URL; check API server pod
no such hostDNS can't resolve API server hostnameCheck DNS; update kubeconfig with IP instead
certificate signed by unknown authorityCert trust issueUpdate kubeconfig CA cert; check cert expiry
context deadline exceededFirewall dropping packetsCheck security group/firewall on port 6443
Unauthorized (401)Credentials expired or wrongRe-authenticate; refresh kubeconfig token

Explore More in This Category

Explore more in this category: Kubernetes guides. Browse all DevOps Compass articles or jump to: Kubernetes, AWS, CI/CD, Containers, Monitoring, Networking.