Bolt Protocol handshake specification

All Bolt connections begin with a handshake to negotiate which version of the messaging protocol to use. Following a successful negotiation, the agreed messaging protocol then takes ownership of the connection for the remainder of its lifetime. The handshake itself is not versioned.

Bolt is a client-server protocol designed primarily for executing queries against a database server. Communication occurs through request-response exchanges, in much the same way as HTTP. Unlike HTTP, however, Bolt connections are stateful.

Byte values are represented using hexadecimal notation unless otherwise specified.

Endianness

Bolt requires that all values that can vary by endianness should be transmitted using network byte order, also known as big-endian byte order. This means that the most significant part of the value is written to the network or memory space first and the least significant part is written last.

Connection and disconnection

Bolt communication is intended to take place over a TCP connection. The default port is TCP 7687 but any port can be used.

There is no formal shutdown procedure for a Bolt connection. Either peer may close the connection at TCP level at any time. Both client and server should be prepared for that to occur and should handle it appropriately.

Handshake

Immediately following a successful connection, the client MUST initiate a handshake. This handshake is a fixed exchange used to determine the version of messaging protocol that follows.

Bolt identification

The first part of the handshake is used to identify to the server that this is a Bolt connection. It should be sent by a client immediately following the establishment of a successful connection and does not require a server response.

The identification consists of the following four bytes:

C: 60 60 B0 17

Version negotiation

After identification, a small client-server exchange occurs to determine which version of the messaging protocol to use. In this, the client submits exactly four protocol versions, each encoded as a big-endian 32-bit unsigned integer for a total of 128 bits. Protocol version zero can be used as a placeholder if fewer than four versions are required in the exchange. Should a match be found for a version supported by the server, the response will contain that version encoded as a single 32-bit integer. If no match is found, a zero value is returned followed by immediate closure of the connection by the server.

Within this exchange, a zero value (four zero bytes) always represents “no protocol version”. For the client, this can be used as a filler if fewer than four protocol versions are known. For the server, this indicates no version match has been found.

A server should assume that the versions contained within a client’s request have been sent in order of preference. Therefore, if a match occurs for more than one version, the first match should be selected.

Example where the client is aware of the Bolt protocol version 1 and the server responds with version 1.
C: 60 60 B0 17
C: 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00
S: 00 00 00 01
Example where the client is aware of the Bolt protocol versions 1 and 2, and the server responds with version 2.
C: 60 60 B0 17
C: 00 00 00 02 00 00 00 01 00 00 00 00 00 00 00 00
S: 00 00 00 02
Example where the client is aware of the Bolt protocol versions 1, 2 and 3, and the server responds with version 2.
C: 60 60 B0 17
C: 00 00 00 03 00 00 00 02 00 00 00 01 00 00 00 00
S: 00 00 00 02
Example where the client is aware of the Bolt protocol version 3 but the server responds with no version, the server do not support communication with the client.
C: 60 60 B0 17
C: 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00
S: 00 00 00 00

Bolt version 5.7

With bolt version 5.7, a new scheme for handshaking is introduced: Manifest v1.

VarInt

VarInts are transmitted in groups of 7 bits with their least significant bits first. The most significant bit within each byte is used as a continuation bit, indicating that more data is to follow. As such, it is not to be considered part of the decoded value.

Hex Encoded Binary Decoded (big endian) Decimal Decoded

01

0000 0001

1

7F

0111 1111

127

FF 82 71

0001 1100 0100 0001 0111 1111

1851775

Let’s take apart the last example:

# Encoded in hexadecimal
FF 82 71
# Encoded in binary
1111 1111  1000 0010  0111 0001
# These are the continuation bits specifying how many bytes to read
1... ....  1... ....  0... ....
# Bits of the actual value (in 7-bit groups in little-endian order)
 111 1111   000 0010   111 0001
 ========   ^^^^^^^^   ~~~~~~~~
# Convert to big-endian (if target machine is big-endian)
 111 0001   000 0010   111 1111
 ~~~~~~~~   ^^^^^^^^   ========
# Concatenate bits for the final (big-endian) binary representation
0001 1100  0100 0001  0111 1111
   ~~~~~~~~~~^^^^^^^^^^========

Handshake Manifest v1

The client can substitute one of the 4 32-bit version requests with the special version 00 00 01 FF where the first two bytes are reserved, the next byte is manifest version (here v1), and the last byte FF indicates that this is a manifest style handshake request.

If the server accepts the request, it will respond with 00 00 01 FF, followed by

  • A VarInt N (max unsigned 64-bit integer)

  • An N long list of supported bolt versions in bolt version 4.3 style (4 bytes each).

  • A VarInt CAPABILITIES (max unsigned 64-bit integer), which is a reserved bitmask for vendor-specific protocol amendments.

The client can choose any of the offered versions and replies with

  • The chosen version in bolt version 4.0 style (4 bytes, may not contain a range).

  • A VarInt CAPABILITIES, selecting a subset (or all) of the offered capabilities.

Since no server response it expected after the client’s final part of the handshake, the client can pipeline that with the first Bolt message(s).
Example
C: 60 60 B0 17                                         # (1)
C: 00 00 01 FF  00 00 04 04  00 00 00 03  00 00 00 02  # (2)
S: 00 00 01 FF                                         # (3)
S: 02                                                  # (4)
S: 00 02 08 05                                         # (4a)
S: 00 04 04 04                                         # (4b)
S: 09                                                  # (5)
C: 00 00 07 05                                         # (6)
C: 08                                                  # (7)
  1. Bolt identification

  2. Client requests (in order of preference)

    • Manifest v1

    • Highest available of Bolt versions 4.4 - 4.0

    • Bolt version 3

    • Bolt version 2

  3. Server chooses manifest v1

  4. Server announces that 2 supported version(-ranges) are available:

    1. Bolt versions 5.8 - 5.6

    2. Bolt versions 4.4 - 4.0

  5. Server offers capability bits 1 and 4 (bitmask 0000 1001)

  6. Client chooses Bolt version 5.7

  7. Client chooses capability bit 4 (bitmask 0000 1000)

Bolt version 4.3

With Bolt version 4.3, the version scheme supports ranges of minor versions. The first 8 bits are reserved. The next 8 bits represent the number of consecutive minor versions below the specified minor (next 8 bits) and major (next 8 bits) version that are supported.

The range cannot span multiple major versions.

Example with versions 4.3 plus two previous minor versions, 4.2 and 4.1
00 02 03 04
Example where the client is aware of five Bolt versions; 3, 4.0, 4.1, 4.2 and 4.3, and the server responds with 4.1
C: 60 60 B0 17
C: 00 03 03 04 00 00 01 04 00 00 00 04 00 00 00 03
S: 00 00 01 04

The client has to specify all versions prior to 4.3 explicitly since servers that only support those protocol versions might not support ranges. The example makes use of the fact that Bolt 4.1 and 4.2 are equivalent and only offer 4.3, 4.2, 4.0, and 3, but specify a range (4.3-4.0), in case the server supports ranges.

Bolt version 4.0

With Bolt version 4.0 the version scheme supports major and minor versioning number. The first 16 bits are reserved. 8 bits represent the minor version. 8 bits represent the major version.

Example with version 4.1
00 00 01 04
Example where the client is aware of three Bolt versions; 3, 4.0 and 4.1, and the server responds with 4.1.
C: 60 60 B0 17
C: 00 00 01 04 00 00 00 04 00 00 00 03 00 00 00 00
S: 00 00 01 04