io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: no further information reads like a hard failure and is actually the most encouraging error in this family. Something at that address answered your packet within milliseconds, deliberately, to say nothing is listening here.
Why a refusal is better than silence ¶
A TCP refusal is an RST packet sent by the destination host itself. To send it, the machine must be powered on, connected, reachable across the whole internet path, and not hidden behind a firewall that silently drops traffic. Every one of those is now confirmed.
Compare with Connection timed out, where none of it is confirmed and the problem could be anywhere along the path. A refusal narrows the search to one machine and one port.
1. The server process is not running ¶
The obvious one, and here it is genuinely likely rather than merely possible. The host is up; the Minecraft server on it is not. It crashed, failed to start, or was never started after a reboot.
Check the console or the service manager rather than trusting that it "should" be running. A server that failed to bind its port often exits within a second of starting, and a startup script that reports success can still leave nothing listening. On Linux, ss -tlnp | grep 25565 answers this definitively.
2. It is listening on a different port ¶
The client defaults to 25565. If server-properties sets something else, connecting without a port refuses immediately, because nothing is on 25565 while the server sits happily on another number.
Connect with the port explicitly: address:25566. This is also the failure mode when several servers share one machine, which is the normal setup for anyone running a test world beside a live one.
3. It is bound to localhost only ¶
A subtle one that produces a confusing symptom: the server works perfectly from the machine it runs on and refuses every connection from anywhere else. That happens when server-ip in server.properties is set to 127.0.0.1, or when a container publishes the port only on the loopback interface.
Leave server-ip blank to listen on every interface. That blank value is the correct setting for almost every deployment, and setting it to the machine's own address is a common misreading of what the field is for.
4. Port forwarding sends traffic to the wrong machine ¶
A router rule pointing at an internal address that no longer belongs to the server, usually after DHCP reassigned it, forwards your connection to a machine that is on and has nothing listening. That machine refuses, and you see this error even though the server itself is fine.
Give the server a static DHCP reservation. Every home server outgrows a dynamic lease eventually, and the failure it produces looks nothing like its cause.
Diagnosing from outside ¶
Our checker queries a Minecraft server with its own protocol and reports what came back. Three outcomes, three conclusions:
- Full MOTD and player count: the server is up and answering the public internet. Your client is the odd one out — check the port and the address you typed.
- No response: nothing is listening where you pointed us either. The refusal is real and consistent.
- Answers on a different port than you expected: the port is the problem, and you have just found it.
When it is a proxy rather than the server ¶
Networks running BungeeCord or Velocity have two layers: the proxy, which players connect to, and the backend servers behind it. A refusal on the public port means the proxy is down. A working proxy with a backend refusing produces a different message entirely, usually a kick with text about being unable to connect to the world.
If you see the in-game kick rather than a connection error, the proxy is healthy and the problem is one server behind it, which is a much smaller thing to fix.
Quick checklist ¶
- Is the process actually listening?
ss -tlnp | grep 25565. - Is it on the port you are connecting to?
- Is
server-ipblank inserver.properties? - Does the router rule point at the server's current internal address?
- Does an outside ping see it?
Containers publish ports differently ¶
If the server runs in Docker or Podman, a refusal usually means the port
was published to the wrong interface. -p 25565:25565 publishes on
every interface; -p 127.0.0.1:25565:25565 publishes on loopback
only, which works from the host and refuses everyone else — the container
version of the server-ip mistake above.
Check what is actually published with docker port <container>
rather than reading the compose file, because a running container keeps the
mapping it was created with and will not pick up an edit until it is
recreated. A restarted container is not a recreated one.
Hosting panels allocate ports for you ¶
On Pterodactyl, Multicraft and similar panels you do not choose the port — the panel assigns an allocation, and the server must be configured to use exactly that one. Two things go wrong routinely:
- Someone edits
server.propertiesto a port the panel has not allocated. The server starts, binds a port nothing is forwarded to, and refuses every external connection. - The panel shows a primary allocation while the server binds a secondary one, so the address in the panel is not the address that works.
The panel's allocation list is authoritative. If it disagrees with
server.properties, the file is wrong.
What to tell players ¶
A refusal is the one connection error where "try again in a minute" is genuinely reasonable advice, because the most common cause is a server that is restarting and has not yet bound its port. If it persists past a couple of minutes, it is configuration rather than timing, and the checklist above is the faster path than another restart.