# Protocol

> How HotKV speaks RESP2 and RESP3 on the wire, HELLO, inline commands, push messages, client names and protocol limits.

URL: https://docs.hotkv.com/reference/protocol/


HotKV speaks RESP, the protocol Redis clients use, over TCP or TLS. Any
client library or tool that works with Redis talks to HotKV without changes.
This page describes the protocol as HotKV implements it. For using RESP3
features from an application, see [RESP3](https://docs.hotkv.com/develop/resp3/index.md).

## Connections

- A new connection starts in **RESP2**. Send [`HELLO 3`](https://docs.hotkv.com/commands/hello/index.md) to
  switch it to RESP3, or `HELLO 2` to switch back.
- Plain-text clients connect to [`port`](https://docs.hotkv.com/reference/configuration/index.md#port)
  (6379 by default), TLS clients to
  [`tls-port`](https://docs.hotkv.com/reference/configuration/index.md#tls-port). Unix domain sockets are not
  supported.
- When the `default` user has a password, a client must authenticate with
  [`AUTH`](https://docs.hotkv.com/commands/auth/index.md) or `HELLO ... AUTH` before running other commands.
- With [`protected-mode`](https://docs.hotkv.com/reference/configuration/index.md#protected-mode) on and no
  password set, only clients on the loopback interface are served; others get
  a `DENIED` error and are disconnected. See [Errors](https://docs.hotkv.com/reference/errors/index.md#denied).

## Sending commands

A command is a RESP array of bulk strings: the command name, then its
arguments. Names are case-insensitive; arguments are binary-safe.

```text
*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$5\r\nhello\r\n
```

You can send many commands without waiting for their replies
([pipelining](https://docs.hotkv.com/develop/pipelining/index.md)). Replies always come back in the order
the commands were sent.

### Inline commands

For quick tests with `telnet` or `nc`, HotKV also takes a command as one line
of text ending in `\r\n`, with the arguments separated by spaces:

```text
SET mykey hello
+OK
GET mykey
$5
hello
```

> **Note**
> Inline commands split on spaces only. Quotes and escapes are not interpreted,
> so an argument cannot contain a space, and an empty line is a protocol error.
> Client libraries always use the array form.

## Replies

HotKV sends these reply types:

| Type | Prefix | RESP2 | RESP3 | Used for |
| --- | --- | --- | --- | --- |
| Simple string | `+` | yes | yes | `OK`, `PONG`, status replies |
| Error | `-` | yes | yes | every error (see [Errors](https://docs.hotkv.com/reference/errors/index.md)) |
| Integer | `:` | yes | yes | counts, lengths, flags |
| Bulk string | `$` | yes | yes | values |
| Array | `*` | yes | yes | lists of replies |
| Null | `$-1` / `*-1`, or `_` | yes | yes | missing values |
| Map | `%` | as a flat array | yes | `HELLO`, `CONFIG GET`, `HGETALL`, info-style replies |
| Set | `~` | as an array | yes | `SMEMBERS` and other set replies |
| Double | `,` | as a bulk string | yes | scores (`ZSCORE`, `ZINCRBY`, `WITHSCORES`) |
| Boolean | `#` | as an integer | yes | booleans returned by scripts that call `redis.setresp(3)` |
| Verbatim string | `=` | as a bulk string | yes | text reports (`INFO`, `CLIENT INFO`, `CLIENT LIST`, `LATENCY DOCTOR`) |
| Push | `>` | as an array | yes | pub/sub messages (see below) |

In RESP2 a missing value is a null bulk string (`$-1`) or a null array
(`*-1`), as Redis sends them; in RESP3 both are the null type (`_`).

HotKV does not send RESP3 big numbers or attributes.

## HELLO

```text
HELLO [protover [AUTH username password] [SETNAME clientname]]
```

`HELLO` picks the protocol version for the connection, can authenticate and
name the client in the same round trip, and replies with facts about the
server. `protover` must be `2` or `3`; anything else gets
`NOPROTO unsupported protocol version`. Without arguments it replies in the
connection's current protocol.

```text
127.0.0.1:6379> HELLO 3
1# "server" => "hotkv"
2# "version" => "8.4.0"
3# "proto" => (integer) 3
4# "id" => (integer) 7
5# "mode" => "standalone"
6# "role" => "master"
7# "modules" => (empty array)
```

| Field | Value |
| --- | --- |
| `server` | Always `hotkv`. |
| `version` | The Redis version whose commands and replies HotKV follows, `8.4.0`. Client libraries choose features by it. HotKV's own version is `hotkv_version` in [`INFO server`](https://docs.hotkv.com/commands/info/index.md). |
| `proto` | The protocol now in use. |
| `id` | The connection's client ID, as [`CLIENT ID`](https://docs.hotkv.com/commands/client-id/index.md) returns it. |
| `mode` | `standalone`, or `cluster` on a cluster node. |
| `role` | `master`, or `replica` on a replica. |
| `modules` | Always empty: HotKV does not load modules. |

In RESP2 the same fields come as a flat array of 14 elements.

If the server needs a password and the client has not authenticated, `HELLO`
without `AUTH` fails with a `NOAUTH` error, and `HELLO ... AUTH` with a wrong
password fails with `WRONGPASS`.

## Push messages and pub/sub

A client that subscribes (with [`SUBSCRIBE`](https://docs.hotkv.com/commands/subscribe/index.md),
[`PSUBSCRIBE`](https://docs.hotkv.com/commands/psubscribe/index.md) or [`SSUBSCRIBE`](https://docs.hotkv.com/commands/ssubscribe/index.md))
receives messages it did not ask for at that moment. In RESP3 they arrive as
push replies (`>`); in RESP2 as arrays. The first element names the kind:

| Kind | Elements |
| --- | --- |
| `subscribe`, `psubscribe`, `ssubscribe` | channel or pattern, number of subscriptions now held |
| `unsubscribe`, `punsubscribe`, `sunsubscribe` | channel or pattern, number of subscriptions left |
| `message` | channel, payload |
| `pmessage` | pattern, channel, payload |
| `smessage` | shard channel, payload |
| `invalidate` | array of keys, or null (see below) |
| `tracking-redir-broken` | id of the connection that was redirected to |

[Keyspace notifications](https://docs.hotkv.com/develop/keyspace-notifications/index.md) are delivered the
same way, as messages on `__keyspace@<db>__:` and `__keyevent@<db>__:`
channels. In a cluster, a client subscribed to a shard channel whose slot
moves to another node receives a `sunsubscribe` push for it.

While a RESP2 connection holds any subscription, it may only run `SUBSCRIBE`,
`PSUBSCRIBE`, `SSUBSCRIBE`, their `UNSUBSCRIBE` counterparts, `PING`, `QUIT`
and `RESET`. Other commands get
`ERR Can't execute '<command>': only (P|S)SUBSCRIBE / (P|S)UNSUBSCRIBE / PING / QUIT / RESET are allowed in this context`.
A RESP3 connection can run any command while it is subscribed, because it can
tell a message from a reply.

### Client-side caching pushes

A RESP3 connection that turned on server-assisted client-side caching
([`CLIENT TRACKING`](https://docs.hotkv.com/commands/client-tracking/index.md)) receives a push when a key it
read changes: `>2`, the string `invalidate`, then an array of the keys, or a null
when everything it cached should be forgotten. A connection that redirects its
invalidations to a connection that has gone receives `>2`, the string
`tracking-redir-broken` and the id of that connection. A RESP2 connection
cannot be pushed to: with `REDIRECT` its invalidations arrive on the other
connection as a pub/sub `message` on the channel `__redis__:invalidate`. See
[client-side caching](https://docs.hotkv.com/develop/client-side-caching/index.md).

## Client name and library info

Each connection can carry a name and the client library's name and version,
which show up in [`CLIENT LIST`](https://docs.hotkv.com/commands/client-list/index.md) and
[`CLIENT INFO`](https://docs.hotkv.com/commands/client-info/index.md):

- [`CLIENT SETNAME`](https://docs.hotkv.com/commands/client-setname/index.md) (or `HELLO ... SETNAME`) sets
  the name. Names cannot contain spaces or non-printable characters.
- [`CLIENT SETINFO LIB-NAME`](https://docs.hotkv.com/commands/client-setinfo/index.md) and
  `CLIENT SETINFO LIB-VER` record the library, with the same character rules.
  Client libraries usually send these when they connect.
- [`CLIENT GETNAME`](https://docs.hotkv.com/commands/client-getname/index.md) and
  [`CLIENT ID`](https://docs.hotkv.com/commands/client-id/index.md) read the name and ID back.

`CLIENT LIST` and `CLIENT INFO` describe each connection with these fields:
`id`, `addr`, `laddr`, `fd`, `name`, `age`, `idle`, `flags`, `db`, `sub`,
`psub`, `ssub`, `multi`, `watch`, `qbuf`, `qbuf-free`, `omem`, `tot-mem`,
`events`, `cmd`, `user`, `redir`, `resp`, `lib-name`, `lib-ver`.

Other per-connection controls: [`CLIENT REPLY`](https://docs.hotkv.com/commands/client-reply/index.md)
(`ON`, `OFF`, `SKIP`), [`CLIENT NO-EVICT`](https://docs.hotkv.com/commands/client-no-evict/index.md),
[`CLIENT NO-TOUCH`](https://docs.hotkv.com/commands/client-no-touch/index.md),
[`SELECT`](https://docs.hotkv.com/commands/select/index.md), and [`RESET`](https://docs.hotkv.com/commands/reset/index.md), which returns
the connection to its initial state.

## Protocol limits

| Limit | Value | Configurable |
| --- | --- | --- |
| Longest bulk string a client may send | 512 MB | [`proto-max-bulk-len`](https://docs.hotkv.com/reference/configuration/index.md#proto-max-bulk-len), 1 MB to 4294967295 bytes |
| Most elements in one command (name plus arguments) | 1,048,576 | no |
| Unprocessed input per client | 1 GB | [`client-query-buffer-limit`](https://docs.hotkv.com/reference/configuration/index.md#client-query-buffer-limit) |
| Unprocessed input before authentication | 1 MB | no |
| Unsent output before authentication | 64 KB | no |
| Unsent output per client class | see default | [`client-output-buffer-limit`](https://docs.hotkv.com/reference/configuration/index.md#client-output-buffer-limit) |

A request that breaks the protocol (a malformed header, a bulk string longer
than `proto-max-bulk-len`, too many elements) gets
`ERR Protocol error: invalid RESP data`, and the server then closes the
connection. A client that passes its input or output limit is disconnected.
See [Limits](https://docs.hotkv.com/reference/limits/index.md) for the other limits.