What's happening
You run a kubectl command and get hit with:
The connection to the server localhost:8443 was refused - did you specify the right host or port?
kubectl is trying to reach the Kubernetes API server at localhost:8443 β but nothing is listening there. Three things cause this: the cluster isn't running, kubectl has no valid kubeconfig, or it's pointed at the wrong endpoint. Port 8443 is the Minikube default; kubeadm clusters use 6443. Seeing localhost:8443 on a kubeadm setup is a dead giveaway that your kubeconfig is stale or misconfigured.
Quick diagnosis
Narrow down the cause before touching anything. These four checks cover 95% of cases.
1. Check your current context
kubectl config current-context
An error here β or a context name you don't recognize β is often the whole problem. List everything configured:
kubectl config get-contexts
2. Check if kubeconfig exists
echo $KUBECONFIG
ls ~/.kube/config
No ~/.kube/config? That's your answer. When kubectl finds no config, it falls back to localhost:8443 β which is almost certainly wrong.
3. For local clusters (Minikube / kind)
# Minikube
minikube status
# kind
kind get clusters
A stopped or deleted cluster means kubectl has no API server to connect to.
4. For remote clusters (kubeadm / cloud)
kubectl cluster-info
Cross-check the server address in your kubeconfig against the real API server IP:
kubectl config view --minify | grep server
Fix by scenario
Scenario A: Local cluster is stopped (Minikube / kind)
Nine times out of ten, this is the culprit. Start it back up:
# Minikube
minikube start
# kind (recreate if deleted)
kind create cluster --name my-cluster
Minikube rewrites ~/.kube/config automatically on start. Once it's up, confirm everything looks good:
kubectl get nodes
Scenario B: No kubeconfig or empty config
Fresh machine? Config accidentally deleted? Regenerate it:
# Minikube β regenerates kubeconfig automatically
minikube update-context
# kubeadm β copy the admin config from the control plane node
scp user@control-plane-node:/etc/kubernetes/admin.conf ~/.kube/config
chmod 600 ~/.kube/config
The chmod 600 isn't optional. kubectl silently refuses to use a config file with world-readable permissions.
Cloud providers have their own one-liners:
# AWS EKS
aws eks update-kubeconfig --region us-east-1 --name my-cluster
# GKE
gcloud container clusters get-credentials my-cluster --zone us-central1-a
# AKS
az aks get-credentials --resource-group my-rg --name my-cluster
Scenario C: Wrong context selected
Switch to the right one:
kubectl config use-context my-correct-context
Don't want to change your default context permanently? The --context flag runs a one-off command against any cluster:
kubectl get pods --context=production-cluster
Scenario D: API server is down on a kubeadm cluster
SSH into the control plane and check whether the API server container is actually running:
sudo crictl ps | grep kube-apiserver
# Check kubelet logs for clues
sudo journalctl -u kubelet -n 100
# Confirm the static pod manifest is still there
ls /etc/kubernetes/manifests/kube-apiserver.yaml
If the pod crashed, pull its logs directly:
sudo crictl logs $(sudo crictl ps -a | grep kube-apiserver | awk '{print $1}')
Three things crash the API server most often: expired certificates, etcd going down, or a typo in the manifest flags. Fix the root cause β kubelet will restart the static pod on its own.
Scenario E: Firewall blocking the port
Server running but still unreachable from another machine? Test the connection before blaming the config:
# Test connectivity directly
telnet <api-server-ip> 6443
# or
curl -k https://<api-server-ip>:6443/healthz
Open the port if it's blocked:
# UFW (Ubuntu)
sudo ufw allow 6443/tcp
# firewalld (RHEL/CentOS)
sudo firewall-cmd --permanent --add-port=6443/tcp
sudo firewall-cmd --reload
Worth repeating: kubeadm uses 6443 by default, not 8443. If you're hitting localhost:8443 on a kubeadm cluster, the problem is the kubeconfig server URL β not the firewall.
Scenario F: Stale server URL in kubeconfig
API server moved to a new IP after a rebuild? Update the URL directly in your kubeconfig:
# Update the server URL
kubectl config set-cluster my-cluster --server=https://<new-api-server-ip>:6443
# Confirm the change took effect
kubectl config view --minify | grep server
Verify the fix
kubectl cluster-info
kubectl get nodes
kubectl get pods -A
A healthy cluster returns something like this from kubectl cluster-info:
Kubernetes control plane is running at https://<server>:<port>
CoreDNS is running at https://<server>:<port>/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
Prevent it going forward
- Minikube users: add
minikube startto your dev environment startup script. A 30-second startup beats hunting down this error mid-session. - kubeadm clusters: put
kube-apiserverunder Prometheus + Alertmanager monitoring. Get paged before your developers notice kubectl is broken. - Remote clusters: treat kubeconfig like a password β store it in a secrets manager, and bake
aws eks update-kubeconfigorgcloud get-credentialsinto your onboarding scripts so credentials never expire silently. - Multiple clusters: install
kubectx. Switching contexts withkubectx productioninstead of the fullkubectl config use-contextcommand takes two seconds and removes a whole class of "why is nothing working" moments.

