Skip to content

AxonOps — AI-Native Control Plane for Open Source Data Platforms

Cassandra CQL Native Protocol Specification

The CQL Native Protocol is a frame-based binary protocol that governs all client-server communication in Apache Cassandra. This specification documents the complete protocol including frame format, message types, data encoding, and version-specific features.

The CQL Native Protocol operates over TCP and provides:

  • Request-response messaging with asynchronous multiplexing
  • Binary encoding for efficiency and type safety
  • Version negotiation for backward compatibility
  • Optional compression to reduce bandwidth
  • Server-pushed events for topology and schema changes
VersionCassandraStatusNotable Changes
v11.2DeprecatedInitial release
v22.0DeprecatedBatch, query paging, result metadata flags
v32.1+Supported32K streams, UDT, tuple types, timestamps on queries
v42.2+SupportedCustom payloads, warnings, unset values, dates/times
v54.0+CurrentPer-query keyspace, NOW_IN_SECONDS, duration type, result metadata ID

Protocol version is established during connection:

  1. Client sends STARTUP with desired version in frame header
  2. If server supports this version, connection proceeds
  3. If not, server responds with ERROR containing supported versions
  4. Client reconnects with mutually supported version

Clients should attempt the highest version they support and fall back as needed.


Byte Order

All multi-byte integers in the CQL protocol are encoded in big-endian (network byte order).

TypeSizeDescription
[byte]1Unsigned 8-bit integer
[short]2Unsigned 16-bit integer
[int]4Signed 32-bit integer
[long]8Signed 64-bit integer
TypeFormatDescription
[string][short] length + UTF-8 bytesStandard string (max 65535 bytes)
[long string][int] length + UTF-8 bytesExtended string (max 2GB)
TypeFormatDescription
[bytes][int] length + raw bytesVariable-length bytes; -1 length = null
[short bytes][short] length + raw bytesShort byte sequence (max 65535 bytes)

Null vs Unset Values

A [bytes] value with length -1 represents null. A length of -2 represents "not set" (v4+). These are semantically different: NULL explicitly sets a column to null, while NOT SET leaves the column unchanged in UPDATE operations.

TypeSizeDescription
[uuid]16UUID in standard binary format (big-endian)
TypeFormatDescription
[inet][byte] size + address bytesIPv4 (4 bytes) or IPv6 (16 bytes)
[inetaddr][inet] + [int] portAddress with port number
TypeSizeDescription
[consistency]2Consistency level as unsigned short
TypeFormatDescription
[string list][short] count + repeated [string]List of strings
[string map][short] count + repeated ([string] key + [string] value)String-to-string map
[string multimap][short] count + repeated ([string] key + [string list] values)String-to-string-list map
[bytes map][short] count + repeated ([string] key + [bytes] value)String-to-bytes map

All protocol communication consists of frames. Each frame has a fixed 9-byte header followed by a variable-length body.

Byte: 0 1 2 3 4 5 6 7 8
+----------+----------+----------+----------+----------+----------+----------+----------+----------+
| version | flags | stream_id | opcode | length |
+----------+----------+----------+----------+----------+----------+----------+----------+----------+
| 1 byte | 1 byte | 2 bytes | 1 byte | 4 bytes |
+----------+----------+----------+----------+----------+----------+----------+----------+----------+
OffsetFieldSizeDescription
0version1 byteProtocol version with direction bit
1flags1 byteFrame flags
2-3stream2 bytesStream identifier (big-endian)
4opcode1 byteMessage type
5-8length4 bytesBody length in bytes (big-endian)
Bit 7 (MSB): Direction
0 = Request (client → server)
1 = Response (server → client)
Bits 6-0: Protocol version number

Examples:

Hex ValueBinaryMeaning
0x030000 0011Request, protocol v3
0x831000 0011Response, protocol v3
0x040000 0100Request, protocol v4
0x841000 0100Response, protocol v4
0x050000 0101Request, protocol v5
0x851000 0101Response, protocol v5
BitFlagDescriptionVersions
0COMPRESSIONBody is compressedAll
1TRACINGRequest: enable tracing; Response: tracing ID includedAll
2CUSTOM_PAYLOADCustom payload map includedv4+
3WARNINGResponse contains warning messagesv4+
4USE_BETAEnable beta protocol featuresv5+
5-7ReservedMust be zero-

Flag combinations: Multiple flags may be set. When COMPRESSION is set, all other frame body processing occurs after decompression.

The stream ID enables request-response multiplexing:

  • Range: 0 to 32767 (signed 16-bit, but negative values reserved)
  • Stream 0: Reserved for server-initiated EVENT messages
  • Client streams: 1 to 32767 for client requests
  • Matching: Server responses carry the same stream ID as the request
  • Reuse: Stream IDs may be reused after response received

Stream Limit History

Protocol v1-v2 supported only streams 0-127. Protocol v3+ expanded this to 32768 concurrent streams per connection.

The protocol supports frames up to 256 MB, but the server default is much smaller:

VersionParameterDefault
4.0native_transport_max_frame_size_in_mb16
4.1+native_transport_max_frame_size16MiB

Frame Size Tuning

Increasing the maximum frame size may be necessary for queries returning very large result sets. Most workloads do not need to change the default.


OpcodeNameDescription
0x01STARTUPInitialize connection, negotiate options
0x05OPTIONSQuery server capabilities
0x07QUERYExecute CQL query string
0x09PREPAREPrepare CQL statement for later execution
0x0AEXECUTEExecute prepared statement
0x0BREGISTERSubscribe to server events
0x0DBATCHExecute batch of statements
0x0FAUTH_RESPONSERespond to authentication challenge
OpcodeNameDescription
0x00ERRORError response with code and message
0x02READYConnection initialized successfully
0x03AUTHENTICATEAuthentication required
0x06SUPPORTEDResponse to OPTIONS with capabilities
0x08RESULTQuery/execute result
0x0CEVENTAsynchronous event notification
0x0EAUTH_CHALLENGEAuthentication challenge token
0x10AUTH_SUCCESSAuthentication completed successfully

CQL native protocol connection and authentication sequenceClientServerClientClientServerServerTCP ConnectOptional DiscoveryOPTIONSSUPPORTEDSTARTUP {CQL_VERSION, COMPRESSION, ...}alt[No Authentication Required]READY[Authentication Required]AUTHENTICATE {authenticator class}AUTH_RESPONSE {credentials}loop[Challenge-Response (if needed)]AUTH_CHALLENGE {token}AUTH_RESPONSE {token}AUTH_SUCCESS {final token}Connection ready for queries

The OPTIONS message has an empty body. It requests the server's supported protocol options.

Body: Empty (0 bytes)

Response to OPTIONS containing server capabilities.

Body:

SUPPORTED {
<options>: [string multimap]
}

Standard options:

KeyDescriptionExample Values
CQL_VERSIONSupported CQL versions["3.4.6", "3.4.7"]
COMPRESSIONSupported compression algorithms["lz4", "snappy"]
PROTOCOL_VERSIONSSupported protocol versions["3/v3", "4/v4", "5/v5"]

Initializes the connection with client options.

Body:

STARTUP {
<options>: [string map]
}

Required options:

KeyDescriptionExample
CQL_VERSIONCQL version to use"3.4.6"

Optional options:

KeyDescriptionExampleVersion
COMPRESSIONCompression algorithm"lz4" or "snappy"All
NO_COMPACTDisable COMPACT STORAGE"true"v4+
THROW_ON_OVERLOADThrow error instead of queueing"true"v4+
DRIVER_NAMEDriver identifier"DataStax Java Driver"v5+
DRIVER_VERSIONDriver version"4.17.0"v5+
CLIENT_IDUnique client identifierUUID stringv5+

Indicates successful connection initialization.

Body: Empty (0 bytes)

Indicates authentication is required.

Body:

AUTHENTICATE {
<authenticator>: [string] Java class name of authenticator
}

Common authenticators:

Class NameAuthentication Type
org.apache.cassandra.auth.PasswordAuthenticatorUsername/password
com.datastax.bdp.cassandra.auth.DseAuthenticatorDSE unified auth

Client authentication response.

Body:

AUTH_RESPONSE {
<token>: [bytes] Authentication token
}

For PasswordAuthenticator, the token format is:

NUL + username + NUL + password
(0x00 byte + UTF-8 username + 0x00 byte + UTF-8 password)

Server requests additional authentication data.

Body:

AUTH_CHALLENGE {
<token>: [bytes] Challenge token
}

Authentication completed successfully.

Body:

AUTH_SUCCESS {
<token>: [bytes] Final token (may be empty)
}

Query parameters are used by QUERY, EXECUTE, and BATCH messages. The format varies by protocol version.

Parameter flags (protocol v5+):

BitFlagDescription
0VALUESValues are provided
1SKIP_METADATADon't include metadata in result
2PAGE_SIZEPage size is set
3PAGING_STATEPaging state is provided
4SERIAL_CONSISTENCYSerial consistency is set
5TIMESTAMPDefault timestamp is set
6NAMES_FOR_VALUESValues are named (not positional)
7KEYSPACEKeyspace is specified
8NOW_IN_SECONDSServer time override (v5+)

Query parameters structure:

<query_parameters> {
<consistency>: [consistency]
<flags>: [int] (v5+) or [byte] (v3-v4)
if (flags & VALUES):
if (flags & NAMES_FOR_VALUES):
<n>: [short] number of values
<values>: n × ([string] name + [bytes] value)
else:
<n>: [short] number of values
<values>: n × [bytes] value
if (flags & PAGE_SIZE):
<page_size>: [int]
if (flags & PAGING_STATE):
<paging_state>: [bytes]
if (flags & SERIAL_CONSISTENCY):
<serial_consistency>: [consistency]
if (flags & TIMESTAMP):
<timestamp>: [long] microseconds since epoch
if (flags & KEYSPACE): // v5+
<keyspace>: [string]
if (flags & NOW_IN_SECONDS): // v5+
<now_in_seconds>: [int] seconds since epoch
}

Execute a CQL query string.

Body:

QUERY {
<query>: [long string] CQL query text
<query_parameters>: Query parameters (see above)
}

Prepare a CQL statement for repeated execution.

Body (v3-v4):

PREPARE {
<query>: [long string] CQL statement to prepare
}

Body (v5+):

PREPARE {
<query>: [long string] CQL statement to prepare
<flags>: [int]
if (flags & KEYSPACE):
<keyspace>: [string]
}

Execute a previously prepared statement.

Body (v3-v4):

EXECUTE {
<id>: [short bytes] Prepared statement ID
<query_parameters>: Query parameters
}

Body (v5+):

EXECUTE {
<id>: [short bytes] Prepared statement ID
<result_metadata_id>: [short bytes] Expected result metadata ID
<query_parameters>: Query parameters
}

The result_metadata_id allows the server to skip sending result metadata if it hasn't changed since preparation.

Execute multiple statements in a single request. Logged batches provide atomicity via batchlog replay (eventual completion, not rollback semantics). Unlogged and counter batches do not provide atomicity guarantees.

Body:

BATCH {
<type>: [byte] Batch type
<n>: [short] Number of statements
<statements>: n × statement entries
<consistency>: [consistency]
<flags>: [int] (v5+) or [byte] (v3-v4)
if (flags & SERIAL_CONSISTENCY):
<serial_consistency>: [consistency]
if (flags & TIMESTAMP):
<timestamp>: [long]
if (flags & KEYSPACE): // v5+
<keyspace>: [string]
if (flags & NOW_IN_SECONDS): // v5+
<now_in_seconds>: [int]
}

Batch types:

ValueTypeDescription
0LOGGEDAtomic batch with batch log for recovery
1UNLOGGEDNon-atomic, no batch log
2COUNTERCounter operations only

Batch Performance

Batches are not a performance optimization. They are designed for atomicity across multiple partitions. For single-partition operations, individual statements often perform better.

Statement entry:

<statement> {
<kind>: [byte]
0 = query string
1 = prepared statement ID
if (kind == 0):
<query>: [long string]
else:
<id>: [short bytes]
<n>: [short] Number of values
<values>: n × [bytes] (or name+value pairs if NAMES_FOR_VALUES)
}

ValueNameDescription
0x0000ANYWrite: any node; Read: not supported
0x0001ONESingle replica
0x0002TWOTwo replicas
0x0003THREEThree replicas
0x0004QUORUMMajority: RF/2 + 1
0x0005ALLAll replicas
0x0006LOCAL_QUORUMQuorum within local datacenter
0x0007EACH_QUORUMQuorum in each datacenter
0x0008SERIALLinearizable (Paxos)
0x0009LOCAL_SERIALLinearizable within local DC
0x000ALOCAL_ONESingle replica in local DC

The RESULT message returns query results in various formats.

Body:

RESULT {
<kind>: [int] Result type
<body>: Kind-specific content
}
ValueKindDescription
0x0001VoidNo result data
0x0002RowsRow data with metadata
0x0003Set_keyspaceUSE keyspace confirmation
0x0004PreparedPrepared statement result
0x0005Schema_changeSchema modification result

Returned for statements that don't produce rows (INSERT, UPDATE, DELETE).

Body: Just the kind [int] = 1, no additional data.

Body:

Rows {
<metadata>: Rows metadata
<rows_count>: [int]
<rows_content>: rows_count × row data
}

Rows metadata:

<rows_metadata> {
<flags>: [int]
<columns_count>: [int]
if (flags & HAS_MORE_PAGES):
<paging_state>: [bytes]
if (flags & METADATA_CHANGED): // v5+
<new_metadata_id>: [short bytes]
if NOT (flags & NO_METADATA):
if (flags & GLOBAL_TABLES_SPEC):
<global_keyspace>: [string]
<global_table>: [string]
<column_specs>: columns_count × column_spec_no_table
else:
<column_specs>: columns_count × column_spec_with_table
}

Metadata flags:

BitFlagDescription
0GLOBAL_TABLES_SPECAll columns from same table
1HAS_MORE_PAGESMore pages available
2NO_METADATAMetadata omitted (SKIP_METADATA was set)
3METADATA_CHANGEDResult metadata ID changed (v5+)

Column specification (with table):

<column_spec_with_table> {
<keyspace>: [string]
<table>: [string]
<name>: [string]
<type>: [option] Column data type
}

Column specification (without table):

<column_spec_no_table> {
<name>: [string]
<type>: [option] Column data type
}

Row content:

<row> {
<values>: columns_count × [bytes]
}

Each value is encoded as [bytes] according to its column type. Null values have length -1.

Returned after successful USE statement.

Body:

Set_keyspace {
<keyspace>: [string]
}

Returned after successful PREPARE.

Body (v3-v4):

Prepared {
<id>: [short bytes] Statement ID
<metadata>: Prepared metadata (bound variables)
<result_metadata>: Rows metadata (result columns)
}

Body (v5+):

Prepared {
<id>: [short bytes] Statement ID
<result_metadata_id>: [short bytes]
<metadata>: Prepared metadata
<result_metadata>: Rows metadata
}

Prepared metadata:

<prepared_metadata> {
<flags>: [int]
<columns_count>: [int]
<pk_count>: [int] Number of partition key columns
if (pk_count > 0):
<pk_indices>: pk_count × [short] Column indices
if (flags & GLOBAL_TABLES_SPEC):
<global_keyspace>: [string]
<global_table>: [string]
<column_specs>: columns_count × column_spec_no_table
else:
<column_specs>: columns_count × column_spec_with_table
}

The pk_indices array identifies which bound variables form the partition key, enabling token-aware routing.

Returned after DDL operations.

Body:

Schema_change {
<change_type>: [string] "CREATED" | "UPDATED" | "DROPPED"
<target>: [string] Object type
<options>: Target-specific options
}

Target types and options:

TargetOptions
KEYSPACE<keyspace>: [string]
TABLE<keyspace>: [string], <table>: [string]
TYPE<keyspace>: [string], <type>: [string]
FUNCTION<keyspace>: [string], <function>: [string], <arg_types>: [string list]
AGGREGATE<keyspace>: [string], <aggregate>: [string], <arg_types>: [string list]

Column types are encoded as "options":

<option> {
<id>: [short] Type ID
<value>: Type-specific data (if required)
}
IDCQL TypeWire Encoding
0x0000custom[string] class name + custom encoding
0x0001asciiUTF-8 bytes (ASCII subset)
0x0002bigint8 bytes, signed big-endian
0x0003blobRaw bytes
0x0004boolean1 byte: 0x00 = false, 0x01 = true
0x0005counter8 bytes, signed big-endian
0x0006decimal[int] scale + varint unscaled value
0x0007double8 bytes, IEEE 754 big-endian
0x0008float4 bytes, IEEE 754 big-endian
0x0009int4 bytes, signed big-endian
0x000A(Reserved)
0x000Btimestamp8 bytes, milliseconds since Unix epoch
0x000Cuuid16 bytes, standard UUID binary format
0x000Dvarchar/textUTF-8 bytes
0x000EvarintVariable-length two's complement
0x000Ftimeuuid16 bytes, Type 1 UUID
0x0010inet4 bytes (IPv4) or 16 bytes (IPv6)
0x0011date4 bytes, unsigned days since epoch (2^31 = Jan 1, 1970)
0x0012time8 bytes, nanoseconds since midnight
0x0013smallint2 bytes, signed big-endian
0x0014tinyint1 byte, signed
0x0015durationvarint months + varint days + varint nanoseconds

decimal:

<decimal> {
<scale>: [int] Number of decimal places
<unscaled>: [varint] Unscaled integer value
}
Value = unscaled × 10^(-scale)

varint:

Variable-length two's complement integer
Minimum bytes needed to represent the value
Sign-extended as needed
Examples:
0 → 0x00
127 → 0x7F
128 → 0x0080
-1 → 0xFF
-128 → 0x80
-129 → 0xFF7F

date:

Unsigned 32-bit integer
Days since January 1, 1970 (Unix epoch)
With offset: value 2^31 (0x80000000) = January 1, 1970
Range: -5877641-06-23 to 5881580-07-11

time:

64-bit signed integer
Nanoseconds since midnight
Range: 0 to 86399999999999

duration:

<duration> {
<months>: [varint]
<days>: [varint]
<nanoseconds>: [varint]
}
Each component uses zigzag encoding for the varint

inet:

IPv4: 4 bytes, network byte order
IPv6: 16 bytes, network byte order
No length prefix - inferred from value length
IDCQL TypeType Option Value
0x0020list<element_type>: [option]
0x0021map<key_type>: [option], <value_type>: [option]
0x0022set<element_type>: [option]

Collection value encoding:

List/Set:
<n>: [int] Number of elements
<elements>: n × [bytes] encoded element values
Map:
<n>: [int] Number of key-value pairs
<entries>: n × ([bytes] key + [bytes] value)
IDType Option Value
0x0030<keyspace>: [string], <name>: [string], <n>: [short], <fields>: n × ([string] field_name + [option] field_type)

UDT value encoding:

<udt_value> {
<fields>: n × [bytes] field values in definition order
}
Null fields encoded with length -1
Missing trailing fields assumed null
IDType Option Value
0x0031<n>: [short], <types>: n × [option]

Tuple value encoding:

<tuple_value> {
<elements>: n × [bytes] element values in definition order
}

Body:

ERROR {
<code>: [int] Error code
<message>: [string] Human-readable description
<additional>: Error-specific additional data
}
CodeNameDescription
0x0000Server errorUnexpected server-side error
0x000AProtocol errorInvalid protocol message
CodeNameDescription
0x0100Bad credentialsAuthentication failed
CodeNameAdditional Data
0x1000Unavailable<consistency>, <required>: [int], <alive>: [int]
0x1001OverloadedNone
0x1002Is_bootstrappingNone
0x1003Truncate_errorNone
0x1100Write_timeoutSee below
0x1200Read_timeoutSee below
0x1300Read_failureSee below
0x1400Function_failure<keyspace>, <function>, <arg_types>
0x1500Write_failureSee below
0x1600CDC_write_failureNone (v5+)
0x1700CAS_write_unknownSee below (v5+)
CodeNameAdditional Data
0x2000Syntax_errorNone
0x2100UnauthorizedNone
0x2200InvalidNone
0x2300Config_errorNone
0x2400Already_exists<keyspace>, <table> (empty if keyspace)
0x2500Unprepared<id>: [short bytes] Statement ID

Handling Unprepared Errors

When receiving an Unprepared error (0x2500), the driver should automatically re-prepare the statement and retry. Most drivers handle this transparently.

Write_timeout (0x1100):

<write_timeout_data> {
<consistency>: [consistency]
<received>: [int] Acknowledgments received
<required>: [int] Acknowledgments required
<write_type>: [string]
<contentions>: [short] (only for CAS, v5+)
}

Write types:

  • SIMPLE - Single partition, non-batch
  • BATCH - Logged batch
  • UNLOGGED_BATCH - Unlogged batch
  • COUNTER - Counter operation
  • BATCH_LOG - Batch log write
  • CAS - Compare-and-set (LWT)
  • VIEW - Materialized view update
  • CDC - CDC write

Read_timeout (0x1200):

<read_timeout_data> {
<consistency>: [consistency]
<received>: [int] Responses received
<required>: [int] Responses required
<data_present>: [byte] 0 = no data, 1 = data received
}

Read_failure (0x1300):

<read_failure_data> {
<consistency>: [consistency]
<received>: [int]
<required>: [int]
<num_failures>: [int]
<failure_map>: Map of endpoint → error code (v5+)
<data_present>: [byte]
}

Write_failure (0x1500):

<write_failure_data> {
<consistency>: [consistency]
<received>: [int]
<required>: [int]
<num_failures>: [int]
<failure_map>: Map of endpoint → error code (v5+)
<write_type>: [string]
}

Failure map (v5+):

<failure_map> {
<n>: [int]
<entries>: n × (<endpoint>: [inetaddr] + <error_code>: [short])
}

CAS_write_unknown (0x1700, v5+):

<cas_write_unknown_data> {
<consistency>: [consistency]
<received>: [int]
<required>: [int]
}

Subscribe to server-pushed events.

Body:

REGISTER {
<event_types>: [string list]
}

Event types:

  • TOPOLOGY_CHANGE - Node added or removed
  • STATUS_CHANGE - Node up or down
  • SCHEMA_CHANGE - Schema modifications

Server responds with READY upon successful registration.

Pushed by server on stream 0.

Body:

EVENT {
<type>: [string] Event type
<data>: Type-specific event data
}
TOPOLOGY_CHANGE {
<change>: [string] "NEW_NODE" | "REMOVED_NODE"
<address>: [inetaddr]
}
STATUS_CHANGE {
<change>: [string] "UP" | "DOWN"
<address>: [inetaddr]
}

Same format as Schema_change result:

SCHEMA_CHANGE {
<change_type>: [string] "CREATED" | "UPDATED" | "DROPPED"
<target>: [string]
<options>: Target-specific data
}

Compression is negotiated during STARTUP. When enabled, the frame body (not header) is compressed.

When using LZ4:

<compressed_body> {
<uncompressed_length>: [int] Original body length (big-endian)
<compressed_data>: LZ4-compressed bytes
}

The frame header's length field contains the compressed size (including the 4-byte uncompressed length).

When using Snappy, the body is compressed using Snappy framing format. No additional length prefix is added.

Implementations typically skip compression for small frames where overhead exceeds benefit. A common threshold is 512 bytes.

Compression Recommendation

LZ4 compression is recommended for most workloads due to its excellent speed-to-ratio balance. Enable compression in the STARTUP message to reduce bandwidth usage.


When the TRACING flag is set on a request:

  1. Server enables tracing for that request
  2. Response includes tracing ID in the body prefix
  3. Tracing data stored in system_traces keyspace

Response body with tracing:

<traced_response> {
<tracing_id>: [uuid]
<normal_body>: Original response body
}

Trace data can be queried from:

  • system_traces.sessions - Session metadata
  • system_traces.events - Detailed trace events

Tracing Overhead

Tracing adds significant overhead to request processing. Use it for debugging specific issues, not in production traffic.


Custom payloads allow drivers and servers to exchange implementation-specific data.

When CUSTOM_PAYLOAD flag is set:

<payload_prefix> {
<payload>: [bytes map]
}

This prefix appears before the normal message body in both requests and responses.

Common uses:

  • Driver-specific metadata
  • Proxy routing information
  • Custom authentication tokens

  • Custom payload support (CUSTOM_PAYLOAD flag)
  • Warning messages in responses (WARNING flag)
  • "Not set" value encoding (length -2)
  • date and time types
  • Failure maps in error responses
  • Schema change notifications for functions/aggregates
  • 4-byte flags field (was 1 byte)
  • Per-query keyspace
  • NOW_IN_SECONDS parameter
  • Result metadata ID for EXECUTE optimization
  • duration type
  • Failure reason codes in error maps
  • METADATA_CHANGED flag in results
  • CAS_write_unknown error

All multi-byte values use big-endian (network) byte order.

All strings are UTF-8 encoded.

  • [bytes] with length -1 represents null
  • [bytes] with length -2 represents "not set" (v4+)
  • "Not set" differs from null in UPDATE operations:
    • NULL explicitly sets column to null
    • NOT SET leaves column unchanged
ResourceDefault Limit
Max frame size16 MiB (default; protocol allows up to 256 MB)
Max streams32768
Max concurrent connections per IPUnlimited

Servers enforce request timeouts configured in cassandra.yaml. Clients should implement their own timeouts and handle partial responses appropriately.