diff --git a/src/NATS.Server/ClientFlags.cs b/src/NATS.Server/ClientFlags.cs
new file mode 100644
index 0000000..8f9e915
--- /dev/null
+++ b/src/NATS.Server/ClientFlags.cs
@@ -0,0 +1,41 @@
+namespace NATS.Server;
+
+///
+/// Connection state flags tracked per client.
+/// Corresponds to Go server/client.go clientFlag bitfield.
+/// Thread-safe via Interlocked operations on the backing int.
+///
+[Flags]
+public enum ClientFlags
+{
+ ConnectReceived = 1 << 0,
+ FirstPongSent = 1 << 1,
+ HandshakeComplete = 1 << 2,
+ CloseConnection = 1 << 3,
+ WriteLoopStarted = 1 << 4,
+ IsSlowConsumer = 1 << 5,
+ ConnectProcessFinished = 1 << 6,
+}
+
+///
+/// Thread-safe holder for client flags using Interlocked operations.
+///
+public sealed class ClientFlagHolder
+{
+ private int _flags;
+
+ public void SetFlag(ClientFlags flag)
+ {
+ Interlocked.Or(ref _flags, (int)flag);
+ }
+
+ public void ClearFlag(ClientFlags flag)
+ {
+ Interlocked.And(ref _flags, ~(int)flag);
+ }
+
+ public bool HasFlag(ClientFlags flag)
+ {
+ return (Volatile.Read(ref _flags) & (int)flag) != 0;
+ }
+}
diff --git a/tests/NATS.Server.Tests/ClientFlagsTests.cs b/tests/NATS.Server.Tests/ClientFlagsTests.cs
new file mode 100644
index 0000000..9958c52
--- /dev/null
+++ b/tests/NATS.Server.Tests/ClientFlagsTests.cs
@@ -0,0 +1,53 @@
+namespace NATS.Server.Tests;
+
+public class ClientFlagsTests
+{
+ [Fact]
+ public void SetFlag_and_HasFlag_work()
+ {
+ var holder = new ClientFlagHolder();
+ holder.HasFlag(ClientFlags.ConnectReceived).ShouldBeFalse();
+
+ holder.SetFlag(ClientFlags.ConnectReceived);
+ holder.HasFlag(ClientFlags.ConnectReceived).ShouldBeTrue();
+ }
+
+ [Fact]
+ public void ClearFlag_removes_flag()
+ {
+ var holder = new ClientFlagHolder();
+ holder.SetFlag(ClientFlags.ConnectReceived);
+ holder.SetFlag(ClientFlags.IsSlowConsumer);
+
+ holder.ClearFlag(ClientFlags.ConnectReceived);
+
+ holder.HasFlag(ClientFlags.ConnectReceived).ShouldBeFalse();
+ holder.HasFlag(ClientFlags.IsSlowConsumer).ShouldBeTrue();
+ }
+
+ [Fact]
+ public void Multiple_flags_can_be_set_independently()
+ {
+ var holder = new ClientFlagHolder();
+ holder.SetFlag(ClientFlags.ConnectReceived);
+ holder.SetFlag(ClientFlags.WriteLoopStarted);
+ holder.SetFlag(ClientFlags.FirstPongSent);
+
+ holder.HasFlag(ClientFlags.ConnectReceived).ShouldBeTrue();
+ holder.HasFlag(ClientFlags.WriteLoopStarted).ShouldBeTrue();
+ holder.HasFlag(ClientFlags.FirstPongSent).ShouldBeTrue();
+ holder.HasFlag(ClientFlags.IsSlowConsumer).ShouldBeFalse();
+ }
+
+ [Fact]
+ public void SetFlag_is_thread_safe()
+ {
+ var holder = new ClientFlagHolder();
+ var flags = Enum.GetValues();
+
+ Parallel.ForEach(flags, flag => holder.SetFlag(flag));
+
+ foreach (var flag in flags)
+ holder.HasFlag(flag).ShouldBeTrue();
+ }
+}