# Connection lifecycle

> How the protocol version is packed and checked, and the login-register handshake that authenticates a connection.

Rendered page: https://iggy.apache.org/docs/binary-protocol/connection-lifecycle/

Source: https://github.com/apache/iggy-website/blob/main/content/docs/binary-protocol/connection-lifecycle.mdx

Docs version: server 0.9.0, Rust SDK 0.11.0, CLI 0.14.0, Node.js SDK 0.10.0, and the Python, Java, Go and C# SDKs at 0.9.0

## Protocol version

The protocol version is a semver packed into one u32, 10 bits per component (each must be below 1024):

```text
bits 31..30  reserved (zero)
bits 29..20  major
bits 19..10  minor
bits  9..0   patch
value = major << 20 | minor << 10 | patch
```

Integer order equals semver order. The value tracks the `iggy_binary_protocol` crate release. Under 0.x the compatibility gate is minor-scoped: the server accepts a client whose packed version is at least the server's minimum and whose `major.minor` is at most the server's. Patch releases never change the wire, so the upper bound ignores patch. The implemented minimum is the current version with its patch component zeroed. Compatibility across minor versions after 1.0.0 requires a future change to that calculation.

## Login-register

The only way to authenticate is the register handshake: command code **40** (`LOGIN_REGISTER`, username and password) or **45** (`LOGIN_REGISTER_WITH_PAT`, personal access token). Both ride `operation = 1` (`Register`) with `session = 0`, `request = 0`, and a non-zero `client` id. Mint a fresh id for a new logical client. A client resuming an existing identity must retain its request counter and use the new session epoch returned by registration.

Both request bodies begin with the `ClientVersionInfo` prefix, so the server can gate on the version before touching credentials:

```text
[protocol_version: u32]
[sdk_name_len: u8][sdk_name: UTF-8, 1-255 bytes]
[sdk_version_len: u8][sdk_version: UTF-8, 1-255 bytes]
```

`protocol_version` is the packed version of the protocol the client was built against. `sdk_name` identifies the SDK (for example `rust-sdk`, `go-sdk`). `sdk_version` is the SDK's own build version.

After the prefix:

**`LOGIN_REGISTER` (code 40):**

```text
[ClientVersionInfo]
[username_len: u8][username: N]
[password_len: u8][password: N]
[context_len: u32][context: N, only when context_len > 0]
```

**`LOGIN_REGISTER_WITH_PAT` (code 45):**

```text
[ClientVersionInfo]
[token_len: u8][token: N]
[context_len: u32][context: N, only when context_len > 0]
```

An incompatible protocol version is answered with a 256-byte `Eviction` frame, reason `14` (`IncompatibleProtocol`), carrying the accepted window at bytes 144 (max) and 148 (min) as packed u32 versions. A body without a decodable `ClientVersionInfo` prefix gets reason `15` (`MalformedLogin`) with a zero window. Bad credentials get reasons 9-11. See [EvictionHeader](https://iggy.apache.org/docs/binary-protocol/framing#evictionheader) for the frame layout.

A successful login is a normal `Reply` with `status = 0`. Its body includes an empty [result section](https://iggy.apache.org/docs/binary-protocol/framing#result-section) before the login payload:

```text
[result_count: u32 = 0]
[user_id: u32]
[session: u64]
[server_protocol_version: u32]
[server_version_len: u8][server_version: N]
```

The client stores `session` and echoes it in every subsequent request header. Logout is command code **39** (`LOGOUT_USER`), `operation = 3` (`Logout`), empty body.

The legacy login commands **38** (`LOGIN_USER`) and **44** (`LOGIN_WITH_PERSONAL_ACCESS_TOKEN`) are refused: the server answers them with an `Eviction` frame, reason `15` (`MalformedLogin`). Only `PING` is accepted before login. Every other command on an unauthenticated connection is denied.
