A Minecraft connection moves through a fixed set of protocol states. Each
state defines its own clientbound and serverbound packet tables; packet ids
are local to a (state, direction) pair.
The states are enumerated in net.minecraft.network.ConnectionProtocol:
HANDSHAKING (handshake)STATUS (status)LOGIN (login)CONFIGURATION (configuration)PLAY (play)The direction is net.minecraft.network.protocol.PacketFlow:
SERVERBOUND — client → server.CLIENTBOUND — server → client.The packet tables live in
HandshakeProtocols, StatusProtocols, LoginProtocols,
ConfigurationProtocols, and GameProtocols.
Once a transition fires, the previous state's packet table no longer applies. A client that receives an out-of-state packet treats it as a fatal protocol error.
A new connection always starts in HANDSHAKING. The client sends exactly one
packet:
HandshakePacketTypes.CLIENT_INTENTION. Fields:
| Field | Type | Notes |
|---|---|---|
| Protocol Version | VarInt | Server compares against its supported set. |
| Server Address | String (≤255) | Hostname the client believes it is reaching. |
| Server Port | Unsigned Short | TCP port (informational). |
| Next State | VarInt | 1 STATUS, 2 LOGIN, 3 TRANSFER. |
The server immediately switches to the requested state. There is no clientbound handshake packet.
TRANSFER is encoded the same as LOGIN and proceeds through the Login
state identically; the server's ServerLoginPacketListenerImpl may use the
intent to allow a "transferred" connection (sent via the Play state's
ClientboundTransferPacket from another server) to bypass certain checks.
Used by the server-list ping. Two clientbound packets, two serverbound.
Canonical exchange:
The server may close the connection at any point after responding. Either ping or status may be omitted by the client.
Used to authenticate the player and to negotiate compression and custom-payload extensions. Canonical successful flow:
Side packets that may interleave:
S -> C Custom Query / C -> S Custom Query Answer — channel-tagged
arbitrary payload.S -> C Cookie Request / C -> S Cookie Response — read a
client-side persistent cookie.S -> C Login Disconnect — terminates the connection. The reason is a
JSON Text Component (legacy String
form), not the NBT form used elsewhere.Encryption is mandatory for online-mode servers and optional for offline
mode. When enabled, all subsequent bytes — including the Login Compression packet itself — pass through the AES/CFB8 layer.
When the client receives Login Finished, it must respond with Login Acknowledged. The server transitions to CONFIGURATION upon reading that
packet; the client transitions immediately upon sending it.
Used to push registries, tags, resource packs, server brand and any other "static" world data before play begins. Either side may interleave its packets freely; the canonical order in a vanilla join is:
Side packets allowed during configuration:
Client Information (C → S) — locale, view distance, chat mode, displayed
skin layers, main hand, text filtering, allow server listings, particle
status. Sent at least once before play.Custom Payload (both directions) — channel + arbitrary bytes.Cookie Request / Cookie Response.Resource Pack Push / Resource Pack Pop / Resource Pack (status).Keep Alive / Ping / Pong.Disconnect (S → C; reason is a Text Component).Store Cookie, Transfer, Update Tags, Custom Report Details,
Server Links, Show Dialog, Clear Dialog, Code Of Conduct,
Accept Code Of Conduct.The Finish Configuration / Acknowledge Finish Configuration round trip
is what actually changes the state.
Carries gameplay. Canonical post-join exchange (after Configuration):
From this point onward both sides exchange packets freely. Keep Alive
must be answered within 30 s or the connection is dropped.
A server may move a playing connection back into the Configuration state at any time (for example to push a new resource pack or a different registry view):
The server's outbound switch happens as soon as it sends Start Configuration; the client does not ack the state change until its play
queue is drained, and the inbound switch on the server side happens on
receipt of Configuration Acknowledged. During the gap the server treats any
PLAY packet from the client normally.
The clientbound Transfer packet is available in both Configuration and
Play. It instructs the client to disconnect and reconnect to a different
host/port. The new connection re-runs Handshake → Login with intent =
TRANSFER (id 3); a server that understands transfer may then skip
authentication based on a previously stored cookie.