## TL;DR
`kubectl` reporting "connection refused" means the CLI cannot reach the Kubernetes API server at all. The usual causes are a wrong or stale kubeconfig context, the cluster being down or unreachable from your network, or a local proxy/port-forward that died. Verify the configured server address first, then check whether anything is actually listening there.

## Error / query
```text
kubectl "connection refused" troubleshooting
```

## Use this skill when
- Every `kubectl` command fails with `The connection to the server [host]:[port] was refused`
- `kubectl cluster-info` fails but other network tools work
- A previously working kubeconfig suddenly stops connecting
- You just switched contexts and commands stopped working

## Not for this skill when
- The error is `Unauthorized` or `Forbidden` (auth/RBAC problem, the connection itself works)
- The error mentions TLS certificates (expired or untrusted certs, not refused connections)
- Only one namespace or resource type fails (permissions, not connectivity)
- You are debugging pod-to-service traffic inside the cluster (that is service networking, not kubectl)

## Steps

### Step 1: See which server kubectl is trying to reach
```bash
kubectl config view --minify
```
Expected: the `server:` address and current context. If the address points at the wrong cluster, a dead port-forward, or `YOUR_THE_HOST loopback address:[port]` from a stopped proxy, you have found it.

### Step 2: Confirm the current context is the one you want
```bash
kubectl config get-contexts
```
Expected: a list of contexts with the current one starred. If the wrong context is active, switch with `kubectl config use-context [name]` and retry.

### Step 3: Test raw TCP connectivity to the API server
```bash
APISERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}')
echo "$APISERVER"
curl -sk --max-time 5 "$APISERVER/healthz"
```
Expected: if curl also fails to connect, the problem is network reachability (cluster down, firewall, VPN off). If curl connects but kubectl does not, suspect the kubeconfig (proxy settings, cert paths).

### Step 4: Check for a dead local proxy or expired credentials file
```bash
ls -la ~/.kube/config
env | grep -i -E "proxy|kube"
```
Expected: the kubeconfig exists and is readable, and no stale `HTTPS_PROXY` is redirecting cluster traffic. A proxy env var set for office traffic is a classic cause of refused connections to internal clusters.

### Step 5: Re-authenticate or regenerate the kubeconfig
```bash
kubectl config use-context [correct-context]
kubectl cluster-info
```
Expected: `Kubernetes control plane is running at [address]`. If it still fails, regenerate the kubeconfig from your cluster provider (cloud console, `az aks get-credentials`, `aws eks update-kubeconfig`, etc.) and retry.

## Variant phrasings

### "kubectl cannot connect to server"
Same thing. Start with step 1; the configured server address is wrong or unreachable in most cases.

### "the connection to the server was refused did you specify the right host or port"
This is the full kubectl error text. It almost always means the kubeconfig points at a dead address, check context and server first.

### "kubectl works on VPN but not off it"
The API server is on a private network. Either connect the VPN or expose the API through an authorized network, per your cluster's access policy.

## Why it happens
kubectl is just an HTTPS client; "connection refused" happens at the TCP layer before any Kubernetes logic runs. Either nothing is listening at that address (wrong host/port, cluster down, dead port-forward) or something in the middle (firewall, missing VPN, bad proxy env) blocks the SYN. The kubeconfig is a local file, so a stale or switched context is the most common root cause.

## Edge cases and pitfalls
- Kind/minikube clusters die when the VM stops; `minikube status` or the docker daemon state tells you fast.
- Multiple kubeconfig files merge via `KUBECONFIG`; a stale entry in a second file can shadow the right one.
- Some corporate proxies intercept and refuse non-proxied HTTPS; add the cluster IP to `NO_PROXY`.
- Port-forwards (`kubectl proxy`, ssh tunnels) die silently; the refused connection is on your machine, not the cluster.
- After a cluster upgrade the API server address or CA can change; regenerate credentials rather than editing the file by hand.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_v9OaRFdSqIg0PMmGDe8OTw
