v2.14.4

nats-io/nats-serverv2.14.4Jul 30, 2026by github-actions[bot]

AI Summary

This release updates Go to version 1.26.5 and focuses on significant JetStream performance enhancements, including faster AVL sequence sets and reduced memory usage. It also addresses several security vulnerabilities, including an MQTT permission bypass and an authentication bypass with TLS.

Key Highlights

  • Raft transport layer decoupling for improved testing and behavior stability.
  • JetStream disk concurrency semaphore increased to 4096 slots and configurable via `max_concurrent_io`.
  • Security fixes: Resolved authentication bypass with TLS `verify_and_map` and MQTT `$MQTT.>` permission bypass.
  • Monitoring: `healthz` endpoint now skips reporting on expired JWT accounts.

New Features

  • JetStream disk concurrency semaphore configuration option `max_concurrent_io`

Full Release Notes

## Changelog

Refer to the [2.14 Upgrade Guide](https://docs.nats.io/release-notes/whats_new/whats_new_214) for backwards compatibility notes with 2.12.x. Please note that the 2.13.x version was skipped.

### Go Version

- 1.26.5 (#8435)

### Dependencies

- github.com/klauspost/compress v1.19.0 (#8385)
- golang.org/x/crypto v0.54.0 (#8385)
- golang.org/x/sys v0.47.0 (#8385)
- github.com/antithesishq/antithesis-sdk-go v0.7.2-default-no-op (#8385)

### Improved

JetStream

- The Raft transport layer has been decoupled, improves testing but does not change server behaviour (#8181)
- The disk concurrency semaphore has been increased to 4096 slots, up from the previous CPU-scaled count (#8336)
- The disk concurrency semaphore can now be configured with the `max_concurrent_io` option in the `jetstream` config block (#8336)
- Filestore underlying block cache buffers are now recycled to the pool when the weak reference is collected by the GC, which should smooth out memory usage with some usage patterns (#8395)
- Calculating and looking up sequences in delete maps for file-backed streams with large numbers of interior deletes is now faster and holds locks for less time (#8403)
- Inserts, iterations and deletes in AVL sequence sets are now faster in many cases, which speeds up the tracking of interior deletes (#8406)
- Stream snapshots now attempt to determine the correct encode buffer size up front, avoiding many unnecessary allocations on streams with large numbers of interior deletes (#8405)
- Reduced memory usage of the structure that is used to track subjects within a stream (#8412)

### Fixed

General

- `allow_non_tls` will no longer log an incorrect message at startup claiming that TLS is required (#8420)
- Combining `no_auth_user` with auth callouts will no longer skip authentication checks when no `CONNECT` message is sent
- JWT validation no longer crashes the server with whitespace-only permissions
- Several paths that enforce the permissions of queue subscriptions no longer treat the whole permission as a subject literal
- Several JetStream and MQTT endpoints now correctly guard against null values in JSON
- Fixed an authentication bypass with TLS `verify_and_map` authenticating users with blank passwords

Monitoring

- The `healthz` endpoint will now skip and no longer report on expired JWT accounts (#8379, thanks to @ByapakSigdel)
- The `varz` endpoint will now correctly report JetStream limits after they were changed via a config reload (#8394)

JetStream

- Malformed cluster replicated acks or delivered updates are now correctly rejected by the decoder (#8284, thanks to @uwezkhan)
- Malformed cluster replicated skip or reset updates are now correctly rejected by the decoder (#8345, thanks to @uwezkhan)
- Empty cluster replicated entries are now correctly ignored (#8347, thanks to @uwezkhan)
- Decoded AVL sequence set node counts are now validated correctly on 32-bit systems (#8355, thanks to @uwezkhan)
- Stale error responses on source or mirror creation are now dropped by recreating the subscription (#8356)
- Oversized cluster replicated messages are now validated correctly on 32-bit systems (#8357, thanks to @uwezkhan)
- Raft elections now correctly ignore votes from removed peers (#8353)
- Filestore blocks with unsynced or truncated key files are now removed and counted as lost data instead of failing to recover altogether (#8365)
- Filestore encryption key files are now synced to disk more aggressively (#8366)
- Raft now handles the append entry iterator returning no more entries correctly (#8372)
- Fixed string ownership when handling the expected last sequence per subject in a batch (#8377)
- Fixed a race condition between concurrent message removals via limits that could unexpectedly disable writes into a filestore (#8378)
- Fixed a bug in the filestore which could prevent some filestore block cache references from being weakened correctly, which could result in unexpected memory usage and GC pressure (#8380)
- Attempting to update the consumer storage type now correctly returns an error (#8382)
- Stream publish checks will now correctly reject messages that exceed the maximum store size before proposal (#8389)
- Fixed a race condition between storing messages in the filestore and block compactions (#8400)
- The filestore no longer skips sparse delete blocks when processing deletes from a snapshot (#8404)
- The consumer reset endpoint responses are no longer dropped when sent through a service import (#8407)
- Creating a clustered consumer immediately after creating a clustered stream should no longer respond with a `stream not found` error (#8410)
- Raft proposals now require the term to be passed down from JetStream, preventing situations where stale proposals from a previous term could make changes in a new term after a fast election (#8370)
- Replicated streams that were recreated while a node was down are no longer treated as an update by a returning node processing a snapshot, avoiding stale Raft groups from continuing to run and unexpected behaviour with consumers (#8413)
- Stream snapshot endpoints now more strictly check the reply subject for validity

MQTT

- Packet identifiers for QoS1 and QoS2 are now issued by a monotonic counter, avoiding accidental ID reuse (#8358, thanks to @nberlee)
- Pending QoS1 and QoS2 deliveries should no longer leak when the subscription is downgraded to QoS0 (#8359, thanks to @nberlee)
- QoS2 messages released on a resumed sessions should no longer lose their QoS or packet ID (#8414)
- MQTT clients can no longer subscribe to `$MQTT.>` subjects, closing a potential permission bypass

### Complete Changes
 
https://github.com/nats-io/nats-server/compare/v2.14.3...v2.14.4