Repository: netbirdio/netbird

Issue:
Error on Debian 12 new install (0.28.6)
**Describe the problem**

Fresh install on Debian 12 (Proxmox, specifically; all packages up-to-date) fails to connect with unclear error: 

Error: waiting sso login failed with: rpc error: code = Unknown desc = string field contains invalid UTF-8


**To Reproduce**

- Install Netbird, using script or manual steps for Debian
- run `netbird up`
- Click login link
- Confirm in browser
- Throw keyboard

Note: Same outcome using setup-key

**Are you using NetBird Cloud?**

Yes

**NetBird version**

0.28.6

**NetBird status -d output:**

If applicable, add the `netbird status -d' command output.

**Screenshots**

![image](https://github.com/user-attachments/assets/709e3cbf-8229-4790-a5ff-85557e3cde4f)
![image](https://github.com/user-attachments/assets/485dd7d9-c33d-464e-a175-049929e08c83)

**Additional context**

I have a second Proxmox host, running the same OS and kernel versions, where this worked flawlessly. I have gutted it from the system, started from scratch, and seen the exact same result.


Hints from issue comments:
@tylerbean: client.log
```
2024-07-24T13:25:37-05:00 INFO client/cmd/service_controller.go:24: starting Netbird service
2024-07-24T13:25:37-05:00 INFO client/internal/config.go:147: generating new config /etc/netbird/config.json
2024-07-24T13:25:37-05:00 INFO client/internal/config.go:209: using default Management URL https://api.netbird.io:443
2024-07-24T13:25:37-05:00 INFO client/internal/config.go:233: using default Admin URL https://api.netbird.io:443
2024-07-24T13:25:37-05:00 INFO client/internal/config.go:251: generated new Wireguard key
2024-07-24T13:25:37-05:00 INFO client/internal/config.go:257: generated new SSH key
2024-07-24T13:25:37-05:00 INFO client/internal/config.go:273: using default Wireguard port 51820
2024-07-24T13:25:37-05:00 INFO client/internal/config.go:284: using default Wireguard interface wt0
2024-07-24T13:25:37-05:00 INFO client/internal/config.go:337: filling in interface blacklist with defaults: [ wt0 wt utun tun0 zt ZeroTier wg ts Tailscale tailscale docker veth br- lo ]
2024-07-24T13:25:37-05:00 INFO client/internal/config.go:383: using default DNS route interval 1m0s
2024-07-24T13:25:37-05:00 INFO client/cmd/service_controller.go:64: started daemon server: /var/run/netbird.sock
2024-07-24T13:25:47-05:00 ERRO encryption/message.go:13: failed marshalling message string field contains invalid UTF-8
2024-07-24T13:25:47-05:00 ERRO management/client/grpc.go:322: failed to encrypt message: string field contains invalid UTF-8
2024-07-24T13:25:47-05:00 ERRO client/server/server.go:262: failed login: string field contains invalid UTF-8
2024-07-24T13:25:58-05:00 ERRO encryption/message.go:13: failed marshalling message string field contains invalid UTF-8
2024-07-24T13:25:58-05:00 ERRO management/client/grpc.go:322: failed to encrypt message: string field contains invalid UTF-8
2024-07-24T13:25:58-05:00 ERRO client/server/server.go:262: failed login: string field contains invalid UTF-8
2024-07-24T13:41:28-05:00 ERRO encryption/message.go:13: failed marshalling message string field contains invalid UTF-8
2024-07-24T13:41:28-05:00 ERRO management/client/grpc.go:322: failed to encrypt message: string field contains invalid UTF-8
2024-07-24T13:41:28-05:00 ERRO client/server/server.go:262: failed login: string field contains invalid UTF-8
2024-07-24T13:41:28-05:00 WARN client/server/server.go:419: canceling previous waiting execution
2024-07-24T13:41:40-05:00 ERRO encryption/message.go:13: failed marshalling message string field contains invalid UTF-8
2024-07-24T13:41:40-05:00 ERRO management/client/grpc.go:322: failed to encrypt message: string field contains invalid UTF-8
2024-07-24T13:41:40-05:00 ERRO client/server/server.go:262: failed login: string field contains invalid UTF-8
2024-07-24T13:42:05-05:00 ERRO encryption/message.go:13: failed marshalling message string field contains invalid UTF-8
2024-07-24T13:42:05-05:00 ERRO management/client/grpc.go:322: failed to encrypt message: string field contains invalid UTF-8
2024-07-24T13:42:05-05:00 ERRO client/server/server.go:262: failed login: string field contains invalid UTF-8
2024-07-24T13:42:06-05:00 WARN client/server/server.go:419: canceling previous waiting execution
2024-07-24T13:42:27-05:00 ERRO encryption/message.go:13: failed marshalling message string field contains invalid UTF-8
2024-07-24T13:42:27-05:00 ERRO management/client/grpc.go:322: failed to encrypt message: string field contains invalid UTF-8
2024-07-24T13:42:27-05:00 ERRO client/server/server.go:262: failed login: string field contains invalid UTF-8
```@dd0ke: Same here. Using:
PRETTY_NAME="Debian GNU/Linux 12 (bookworm)"
Exact same workflow.@dd0ke: With a --setup-key:
2024-07-30T13:24:24-04:00 WARN client/cmd/root.go:234: retrying Login to the Management service in 1.015879675s due to error rpc error: code = Unknown desc = string field contains invalid UTF-8
2024-07-30T13:24:26-04:00 WARN client/cmd/root.go:234: retrying Login to the Management service in 811.919366ms due to error rpc error: code = Unknown desc = string field contains invalid UTF-8
2024-07-30T13:24:29-04:00 WARN client/cmd/root.go:234: retrying Login to the Management service in 1.149214279s due to error rpc error: code = Unknown desc = string field contains invalid UTF-8
2024-07-30T13:24:31-04:00 WARN client/cmd/root.go:234: retrying Login to the Management service in 4.251581099s due to error rpc error: code = Unknown desc = string field contains invalid UTF-8
2024-07-30T13:24:37-04:00 WARN client/cmd/root.go:234: retrying Login to the Management service in 4.782064415s due to error rpc error: code = Unknown desc = string field contains invalid UTF-8
Error: login backoff cycle failed: rpc error: code = Unknown desc = string field contains invalid UTF-8@pappz: Could you send to me the output of the `dmidecode -t system` command?@dd0ke: I imagine you meant posting it here? Otherwise let me know.
Here it goes:
# dmidecode 3.4
Getting SMBIOS data from sysfs.
SMBIOS 2.7 present.

Handle 0x0001, DMI type 1, 27 bytes
System Information
        Manufacturer: PC Engines
        Product Name: PC Engines apu4
        Version: 1.0
        Serial Number: ..........
        UUID: Not Settable
        Wake-up Type: Reserved
        SKU Number: 4 GB
        Family: Not Specified

Handle 0x0005, DMI type 32, 11 bytes
System Boot Information
        Status: No errors detected


> On Jul 31, 2024, at 10:58 AM, Zoltan Papp ***@***.***> wrote:
> 
> 
> Could you send to me the output of the dmidecode -t system command?
> 
> —
> Reply to this email directly, view it on GitHub <https://github.com/netbirdio/netbird/issues/2319#issuecomment-2260005609>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AF7LKBMLK4ACWG7FYSIEP7DZPCRK3AVCNFSM6AAAAABLNB3UACVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENRQGAYDKNRQHE>.
> You are receiving this because you commented.
> 

@pappz: Yes, thank you. I was not sure that it has any data that is sensitive for you.
I am curious about the `dmidecode -t baseboard` too. Maybe the board.serial contains invalid characters.@dd0ke: Hi there, and thanks!

Here is the output. 
# dmidecode 3.4
Getting SMBIOS data from sysfs.
SMBIOS 2.7 present.

Handle 0x0002, DMI type 2, 8 bytes
Base Board Information
        Manufacturer: PC Engines
        Product Name: PC Engines apu4
        Version: 1.0
        Serial Number: ..........

No special characters detected here.
Others here could try on other Debian 12 based systems to see if it is generalized.

> On Jul 31, 2024, at 12:18 PM, Zoltan Papp ***@***.***> wrote:
> 
> 
> Yes, thank you. I was not sure that it has any data that is sensitive for you.
> I am curious about the dmidecode -t baseboard too. Maybe the board.serial contains invalid characters.
> 
> —
> Reply to this email directly, view it on GitHub <https://github.com/netbirdio/netbird/issues/2319#issuecomment-2260171905>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AF7LKBNXTHTXOKFSQOD77JLZPC2WPAVCNFSM6AAAAABLNB3UACVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENRQGE3TCOJQGU>.
> You are receiving this because you commented.
> 

@pappz: I think under the hood the **Serial Number: ..........** is an invalid character line.
In [this](https://github.com/netbirdio/netbird/pull/2360) PR I tried to fix it.@pappz: @ekavun
Could you do a test with the fixed version? You can download the NetBird agent binary from [this](https://github.com/netbirdio/netbird/actions/runs/10181214766/artifacts/1760256992
) link:
If you stop the daemon you can start the patched version from a console with this command:
`sudo ./netbird up -F -l debug`@dd0ke: Thanks!
If I run it in foreground with your debug log, it works. If I run it as a daemon, it gives me the same errors.
In daemon, I am asked to login and the errors continue. In foreground, I’m logged in automatically with netbird up.

This only works with your patch, with the limitations I mentioned.

Sorry for not being more thorough, rushing this to you on spotty connection. Happy to test further later. Thanks for the work!

> On Jul 31, 2024, at 3:50 PM, Zoltan Papp ***@***.***> wrote:
> 
> 
> @ekavun <https://github.com/ekavun>
> Could you do a test with the fixed version? You can download the NetBird agent binary from this <https://github.com/netbirdio/netbird/actions/runs/10181214766/artifacts/1760256992> link:
> If you stop the daemon you can start the patched version from a console with this command:
> sudo ./netbird up -F -l debug
> 
> —
> Reply to this email directly, view it on GitHub <https://github.com/netbirdio/netbird/issues/2319#issuecomment-2260574479>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AF7LKBOINERDUNTENERB33LZPDTQZAVCNFSM6AAAAABLNB3UACVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENRQGU3TINBXHE>.
> You are receiving this because you were mentioned.
> 

@pappz: At the first look should not be different in daemon and foreground mode. Could you double check you run the proper binary in daemon mode?
In this PR I extended the error message with extra information:
`failed marshalling message string field contains invalid UTF-8, meta:{hostname:"...`
@dd0ke: I am sure I ran the binary you provided for both modes.
Just tested again to be sure. With a simple ./netbird up, after the login messages, the error is:
Error: waiting sso login failed with: rpc error: code = Unknown desc = string field contains invalid UTF-8

A ./netbird up -F -l debug works fine, without login step.

> On Jul 31, 2024, at 4:25 PM, Zoltan Papp ***@***.***> wrote:
> 
> 
> At the first look should not be different in daemon and foreground mode. Could you double check you run the proper binary in daemon mode?
> In this PR I extended the error message with extra information:
> failed marshalling message string field contains invalid UTF-8, meta:{hostname:"...
> 
> —
> Reply to this email directly, view it on GitHub <https://github.com/netbirdio/netbird/issues/2319#issuecomment-2260651025>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AF7LKBMATAMRYR7GD6SM2PTZPDXUJAVCNFSM6AAAAABLNB3UACVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENRQGY2TCMBSGU>.
> You are receiving this because you were mentioned.
> 

@mlsmaycon: @ekavun this is because the daemon is running with a different binary. 

What you can do to replace it:
```shell
sudo netbird service stop
sudo mv ./netbird $(which netbird)
sudo netbird start
netbird up
```@dd0ke: This did, in fact, fix the issue!
You are wonderful! It’s rare to have this level of swift and efficient.
I’m 1 day old with Netbird so do not know yet its components and architecture.

> On Jul 31, 2024, at 5:15 PM, Maycon Santos ***@***.***> wrote:
> 
> 
> @ekavun <https://github.com/ekavun> this is because the daemon is running with a different binary.
> 
> What you can do to replace it:
> 
> sudo netbird service stop
> sudo mv ./netbird $(which netbird)
> sudo netbird start
> netbird up
> —
> Reply to this email directly, view it on GitHub <https://github.com/netbirdio/netbird/issues/2319#issuecomment-2260765898>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AF7LKBLJOZUOFFIEM7FMDB3ZPD5PNAVCNFSM6AAAAABLNB3UACVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDENRQG43DKOBZHA>.
> You are receiving this because you were mentioned.
> 

@tylerbean: Fixed for me as well, thank you so much@nazarewk: @tylerbean @dd0ke is the issue resolved? can we close this?@mlsmaycon: closing issue due to no recent feedback. Feel free to open a new one if the issue persist or reopen if this was a feature request.

Solution patch:
diff --git a/.github/workflows/golang-test-freebsd.yml b/.github/workflows/golang-test-freebsd.yml
index 6cb5f742..4f13ee30 100644
--- a/.github/workflows/golang-test-freebsd.yml
+++ b/.github/workflows/golang-test-freebsd.yml
@@ -30,6 +30,17 @@ jobs:
           # -e - to faile on first error
           run: |
             set -e -x
-            go build -o netbird client/main.go
-            go test -timeout 5m -p 1 -failfast ./iface/...
-            go test -timeout 5m -p 1 -failfast ./client/...
+            time go build -o netbird client/main.go
+            # check all component except management, since we do not support management server on freebsd
+            time go test -timeout 1m -failfast ./base62/...
+            # NOTE: without -p1 `client/internal/dns` will fail becasue of `listen udp4 :33100: bind: address already in use`
+            time go test -timeout 8m -failfast -p 1 ./client/...
+            time go test -timeout 1m -failfast ./dns/...
+            time go test -timeout 1m -failfast ./encryption/...
+            time go test -timeout 1m -failfast ./formatter/...
+            time go test -timeout 1m -failfast ./iface/...
+            time go test -timeout 1m -failfast ./route/...
+            time go test -timeout 1m -failfast ./sharedsock/...
+            time go test -timeout 1m -failfast ./signal/...
+            time go test -timeout 1m -failfast ./util/...
+            time go test -timeout 1m -failfast ./version/...
diff --git a/client/system/info_linux.go b/client/system/info_linux.go
index db58d913..b6a142bc 100644
--- a/client/system/info_linux.go
+++ b/client/system/info_linux.go
@@ -21,6 +21,26 @@ import (
 	"github.com/netbirdio/netbird/version"
 )
 
+type SysInfoGetter interface {
+	GetSysInfo() SysInfo
+}
+
+type SysInfoWrapper struct {
+	si sysinfo.SysInfo
+}
+
+func (s SysInfoWrapper) GetSysInfo() SysInfo {
+	s.si.GetSysInfo()
+	return SysInfo{
+		ChassisSerial: s.si.Chassis.Serial,
+		ProductSerial: s.si.Product.Serial,
+		BoardSerial:   s.si.Board.Serial,
+		ProductName:   s.si.Product.Name,
+		BoardName:     s.si.Board.Name,
+		ProductVendor: s.si.Product.Vendor,
+	}
+}
+
 // GetInfo retrieves and parses the system information
 func GetInfo(ctx context.Context) *Info {
 	info := _getInfo()
@@ -45,7 +65,8 @@ func GetInfo(ctx context.Context) *Info {
 		log.Warnf("failed to discover network addresses: %s", err)
 	}
 
-	serialNum, prodName, manufacturer := sysInfo()
+	si := SysInfoWrapper{}
+	serialNum, prodName, manufacturer := sysInfo(si.GetSysInfo())
 
 	env := Environment{
 		Cloud:    detect_cloud.Detect(ctx),
@@ -87,20 +108,36 @@ func _getInfo() string {
 	return out.String()
 }
 
-func sysInfo() (serialNumber string, productName string, manufacturer string) {
-	var si sysinfo.SysInfo
-	si.GetSysInfo()
+func sysInfo(si SysInfo) (string, string, string) {
 	isascii := regexp.MustCompile("^[[:ascii:]]+$")
-	serial := si.Chassis.Serial
-	if (serial == "Default string" || serial == "") && si.Product.Serial != "" {
-		serial = si.Product.Serial
+
+	serials := []string{si.ChassisSerial, si.ProductSerial}
+	serial := ""
+
+	for _, s := range serials {
+		if isascii.MatchString(s) {
+			serial = s
+			if s != "Default string" {
+				break
+			}
+		}
+	}
+
+	if serial == "" && isascii.MatchString(si.BoardSerial) {
+		serial = si.BoardSerial
 	}
-	if (!isascii.MatchString(serial)) && si.Board.Serial != "" {
-		serial = si.Board.Serial
+
+	var name string
+	for _, n := range []string{si.ProductName, si.BoardName} {
+		if isascii.MatchString(n) {
+			name = n
+			break
+		}
 	}
-	name := si.Product.Name
-	if (!isascii.MatchString(name)) && si.Board.Name != "" {
-		name = si.Board.Name
+
+	var manufacturer string
+	if isascii.MatchString(si.ProductVendor) {
+		manufacturer = si.ProductVendor
 	}
-	return serial, name, si.Product.Vendor
+	return serial, name, manufacturer
 }
diff --git a/client/system/sysinfo_linux.go b/client/system/sysinfo_linux.go
new file mode 100644
index 00000000..df0f5574
--- /dev/null
+++ b/client/system/sysinfo_linux.go
@@ -0,0 +1,12 @@
+package system
+
+// SysInfo used to moc out the sysinfo getter
+type SysInfo struct {
+	ChassisSerial string
+	ProductSerial string
+	BoardSerial   string
+
+	ProductName   string
+	BoardName     string
+	ProductVendor string
+}
diff --git a/encryption/message.go b/encryption/message.go
index a646fa67..6e4cd739 100644
--- a/encryption/message.go
+++ b/encryption/message.go
@@ -10,7 +10,7 @@ import (
 func EncryptMessage(remotePubKey wgtypes.Key, ourPrivateKey wgtypes.Key, message pb.Message) ([]byte, error) {
 	byteResp, err := pb.Marshal(message)
 	if err != nil {
-		log.Errorf("failed marshalling message %v", err)
+		log.Errorf("failed marshalling message %v, %+v", err, message.String())
 		return nil, err
 	}
 
diff --git a/management/server/account.go b/management/server/account.go
index 16a2851b..5d3ee6dc 100644
--- a/management/server/account.go
+++ b/management/server/account.go
@@ -135,8 +135,8 @@ type AccountManager interface {
 	UpdateIntegratedValidatorGroups(ctx context.Context, accountID string, userID string, groups []string) error
 	GroupValidation(ctx context.Context, accountId string, groups []string) (bool, error)
 	GetValidatedPeers(account *Account) (map[string]struct{}, error)
-	SyncAndMarkPeer(ctx context.Context, peerPubKey string, meta nbpeer.PeerSystemMeta, realIP net.IP) (*nbpeer.Peer, *NetworkMap, []*posture.Checks, error)
-	CancelPeerRoutines(ctx context.Context, peer *nbpeer.Peer) error
+	SyncAndMarkPeer(ctx context.Context, accountID string, peerPubKey string, meta nbpeer.PeerSystemMeta, realIP net.IP) (*nbpeer.Peer, *NetworkMap, []*posture.Checks, error)
+	OnPeerDisconnected(ctx context.Context, accountID string, peerPubKey string) error
 	SyncPeerMeta(ctx context.Context, peerPubKey string, meta nbpeer.PeerSystemMeta) error
 	FindExistingPostureCheck(accountID string, checks *posture.ChecksDefinition) (*posture.Checks, error)
 	GetAccountIDForPeerKey(ctx context.Context, peerKey string) (string, error)
@@ -974,7 +974,7 @@ func (am *DefaultAccountManager) UpdateAccountSettings(ctx context.Context, acco
 		return nil, status.Errorf(status.InvalidArgument, "peer login expiration can't be smaller than one hour")
 	}
 
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -1025,7 +1025,7 @@ func (am *DefaultAccountManager) UpdateAccountSettings(ctx context.Context, acco
 
 func (am *DefaultAccountManager) peerLoginExpirationJob(ctx context.Context, accountID string) func() (time.Duration, bool) {
 	return func() (time.Duration, bool) {
-		unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+		unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 		defer unlock()
 
 		account, err := am.Store.GetAccount(ctx, accountID)
@@ -1124,7 +1124,7 @@ func (am *DefaultAccountManager) warmupIDPCache(ctx context.Context) error {
 
 // DeleteAccount deletes an account and all its users from local store and from the remote IDP if the requester is an admin and account owner
 func (am *DefaultAccountManager) DeleteAccount(ctx context.Context, accountID, userID string) error {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 	account, err := am.Store.GetAccount(ctx, accountID)
 	if err != nil {
@@ -1584,7 +1584,7 @@ func (am *DefaultAccountManager) MarkPATUsed(ctx context.Context, tokenID string
 		return err
 	}
 
-	unlock := am.Store.AcquireAccountWriteLock(ctx, account.Id)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, account.Id)
 	defer unlock()
 
 	account, err = am.Store.GetAccountByUser(ctx, user.Id)
@@ -1667,7 +1667,7 @@ func (am *DefaultAccountManager) GetAccountFromToken(ctx context.Context, claims
 	if err != nil {
 		return nil, nil, err
 	}
-	unlock := am.Store.AcquireAccountWriteLock(ctx, newAcc.Id)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, newAcc.Id)
 	alreadyUnlocked := false
 	defer func() {
 		if !alreadyUnlocked {
@@ -1823,7 +1823,7 @@ func (am *DefaultAccountManager) getAccountWithAuthorizationClaims(ctx context.C
 
 	account, err := am.Store.GetAccountByUser(ctx, claims.UserId)
 	if err == nil {
-		unlockAccount := am.Store.AcquireAccountWriteLock(ctx, account.Id)
+		unlockAccount := am.Store.AcquireWriteLockByUID(ctx, account.Id)
 		defer unlockAccount()
 		account, err = am.Store.GetAccountByUser(ctx, claims.UserId)
 		if err != nil {
@@ -1843,7 +1843,7 @@ func (am *DefaultAccountManager) getAccountWithAuthorizationClaims(ctx context.C
 		return account, nil
 	} else if s, ok := status.FromError(err); ok && s.Type() == status.NotFound {
 		if domainAccount != nil {
-			unlockAccount := am.Store.AcquireAccountWriteLock(ctx, domainAccount.Id)
+			unlockAccount := am.Store.AcquireWriteLockByUID(ctx, domainAccount.Id)
 			defer unlockAccount()
 			domainAccount, err = am.Store.GetAccountByPrivateDomain(ctx, claims.Domain)
 			if err != nil {
@@ -1857,17 +1857,11 @@ func (am *DefaultAccountManager) getAccountWithAuthorizationClaims(ctx context.C
 	}
 }
 
-func (am *DefaultAccountManager) SyncAndMarkPeer(ctx context.Context, peerPubKey string, meta nbpeer.PeerSystemMeta, realIP net.IP) (*nbpeer.Peer, *NetworkMap, []*posture.Checks, error) {
-	accountID, err := am.Store.GetAccountIDByPeerPubKey(ctx, peerPubKey)
-	if err != nil {
-		if errStatus, ok := status.FromError(err); ok && errStatus.Type() == status.NotFound {
-			return nil, nil, nil, status.Errorf(status.Unauthenticated, "peer not registered")
-		}
-		return nil, nil, nil, err
-	}
-
-	unlock := am.Store.AcquireAccountReadLock(ctx, accountID)
-	defer unlock()
+func (am *DefaultAccountManager) SyncAndMarkPeer(ctx context.Context, accountID string, peerPubKey string, meta nbpeer.PeerSystemMeta, realIP net.IP) (*nbpeer.Peer, *NetworkMap, []*posture.Checks, error) {
+	accountUnlock := am.Store.AcquireReadLockByUID(ctx, accountID)
+	defer accountUnlock()
+	peerUnlock := am.Store.AcquireWriteLockByUID(ctx, peerPubKey)
+	defer peerUnlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
 	if err != nil {
@@ -1887,26 +1881,20 @@ func (am *DefaultAccountManager) SyncAndMarkPeer(ctx context.Context, peerPubKey
 	return peer, netMap, postureChecks, nil
 }
 
-func (am *DefaultAccountManager) CancelPeerRoutines(ctx context.Context, peer *nbpeer.Peer) error {
-	accountID, err := am.Store.GetAccountIDByPeerPubKey(ctx, peer.Key)
-	if err != nil {
-		if errStatus, ok := status.FromError(err); ok && errStatus.Type() == status.NotFound {
-			return status.Errorf(status.Unauthenticated, "peer not registered")
-		}
-		return err
-	}
-
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
-	defer unlock()
+func (am *DefaultAccountManager) OnPeerDisconnected(ctx context.Context, accountID string, peerPubKey string) error {
+	accountUnlock := am.Store.AcquireReadLockByUID(ctx, accountID)
+	defer accountUnlock()
+	peerUnlock := am.Store.AcquireWriteLockByUID(ctx, peerPubKey)
+	defer peerUnlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
 	if err != nil {
 		return err
 	}
 
-	err = am.MarkPeerConnected(ctx, peer.Key, false, nil, account)
+	err = am.MarkPeerConnected(ctx, peerPubKey, false, nil, account)
 	if err != nil {
-		log.WithContext(ctx).Warnf("failed marking peer as connected %s %v", peer.Key, err)
+		log.WithContext(ctx).Warnf("failed marking peer as connected %s %v", peerPubKey, err)
 	}
 
 	return nil
@@ -1919,7 +1907,7 @@ func (am *DefaultAccountManager) SyncPeerMeta(ctx context.Context, peerPubKey st
 		return err
 	}
 
-	unlock := am.Store.AcquireAccountReadLock(ctx, accountID)
+	unlock := am.Store.AcquireReadLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
diff --git a/management/server/dns.go b/management/server/dns.go
index 8a889df3..08732ad7 100644
--- a/management/server/dns.go
+++ b/management/server/dns.go
@@ -36,7 +36,7 @@ func (d DNSSettings) Copy() DNSSettings {
 
 // GetDNSSettings validates a user role and returns the DNS settings for the provided account ID
 func (am *DefaultAccountManager) GetDNSSettings(ctx context.Context, accountID string, userID string) (*DNSSettings, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -58,7 +58,7 @@ func (am *DefaultAccountManager) GetDNSSettings(ctx context.Context, accountID s
 
 // SaveDNSSettings validates a user role and updates the account's DNS settings
 func (am *DefaultAccountManager) SaveDNSSettings(ctx context.Context, accountID string, userID string, dnsSettingsToSave *DNSSettings) error {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
diff --git a/management/server/event.go b/management/server/event.go
index 616cea28..93b80922 100644
--- a/management/server/event.go
+++ b/management/server/event.go
@@ -13,7 +13,7 @@ import (
 
 // GetEvents returns a list of activity events of an account
 func (am *DefaultAccountManager) GetEvents(ctx context.Context, accountID, userID string) ([]*activity.Event, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
diff --git a/management/server/file_store.go b/management/server/file_store.go
index 9a146283..6e3536bc 100644
--- a/management/server/file_store.go
+++ b/management/server/file_store.go
@@ -39,8 +39,8 @@ type FileStore struct {
 	mux       sync.Mutex `json:"-"`
 	storeFile string     `json:"-"`
 
-	// sync.Mutex indexed by accountID
-	accountLocks      sync.Map   `json:"-"`
+	// sync.Mutex indexed by resource ID
+	resourceLocks     sync.Map   `json:"-"`
 	globalAccountLock sync.Mutex `json:"-"`
 
 	metrics telemetry.AppMetrics `json:"-"`
@@ -281,26 +281,26 @@ func (s *FileStore) AcquireGlobalLock(ctx context.Context) (unlock func()) {
 	return unlock
 }
 
-// AcquireAccountWriteLock acquires account lock for writing to a resource and returns a function that releases the lock
-func (s *FileStore) AcquireAccountWriteLock(ctx context.Context, accountID string) (unlock func()) {
-	log.WithContext(ctx).Debugf("acquiring lock for account %s", accountID)
+// AcquireWriteLockByUID acquires an ID lock for writing to a resource and returns a function that releases the lock
+func (s *FileStore) AcquireWriteLockByUID(ctx context.Context, uniqueID string) (unlock func()) {
+	log.WithContext(ctx).Debugf("acquiring lock for ID %s", uniqueID)
 	start := time.Now()
-	value, _ := s.accountLocks.LoadOrStore(accountID, &sync.Mutex{})
+	value, _ := s.resourceLocks.LoadOrStore(uniqueID, &sync.Mutex{})
 	mtx := value.(*sync.Mutex)
 	mtx.Lock()
 
 	unlock = func() {
 		mtx.Unlock()
-		log.WithContext(ctx).Debugf("released lock for account %s in %v", accountID, time.Since(start))
+		log.WithContext(ctx).Debugf("released lock for ID %s in %v", uniqueID, time.Since(start))
 	}
 
 	return unlock
 }
 
-// AcquireAccountReadLock AcquireAccountWriteLock acquires account lock for reading a resource and returns a function that releases the lock
+// AcquireReadLockByUID acquires an ID lock for reading a resource and returns a function that releases the lock
 // This method is still returns a write lock as file store can't handle read locks
-func (s *FileStore) AcquireAccountReadLock(ctx context.Context, accountID string) (unlock func()) {
-	return s.AcquireAccountWriteLock(ctx, accountID)
+func (s *FileStore) AcquireReadLockByUID(ctx context.Context, uniqueID string) (unlock func()) {
+	return s.AcquireWriteLockByUID(ctx, uniqueID)
 }
 
 func (s *FileStore) SaveAccount(ctx context.Context, account *Account) error {
diff --git a/management/server/group.go b/management/server/group.go
index 45c51bda..37a6fc30 100644
--- a/management/server/group.go
+++ b/management/server/group.go
@@ -23,7 +23,7 @@ func (e *GroupLinkError) Error() string {
 
 // GetGroup object of the peers
 func (am *DefaultAccountManager) GetGroup(ctx context.Context, accountID, groupID, userID string) (*nbgroup.Group, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -50,7 +50,7 @@ func (am *DefaultAccountManager) GetGroup(ctx context.Context, accountID, groupI
 
 // GetAllGroups returns all groups in an account
 func (am *DefaultAccountManager) GetAllGroups(ctx context.Context, accountID string, userID string) ([]*nbgroup.Group, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -77,7 +77,7 @@ func (am *DefaultAccountManager) GetAllGroups(ctx context.Context, accountID str
 
 // GetGroupByName filters all groups in an account by name and returns the one with the most peers
 func (am *DefaultAccountManager) GetGroupByName(ctx context.Context, groupName, accountID string) (*nbgroup.Group, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -110,7 +110,7 @@ func (am *DefaultAccountManager) GetGroupByName(ctx context.Context, groupName,
 
 // SaveGroup object of the peers
 func (am *DefaultAccountManager) SaveGroup(ctx context.Context, accountID, userID string, newGroup *nbgroup.Group) error {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 	return am.SaveGroups(ctx, accountID, userID, []*nbgroup.Group{newGroup})
 }
@@ -163,7 +163,7 @@ func (am *DefaultAccountManager) SaveGroups(ctx context.Context, accountID, user
 	}
 
 	account.Network.IncSerial()
-	if err = am.Store.SaveGroups(account.Id, account.Groups); err != nil {
+	if err = am.Store.SaveAccount(ctx, account); err != nil {
 		return err
 	}
 
@@ -245,7 +245,7 @@ func difference(a, b []string) []string {
 
 // DeleteGroup object of the peers
 func (am *DefaultAccountManager) DeleteGroup(ctx context.Context, accountId, userId, groupID string) error {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountId)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountId)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountId)
@@ -359,7 +359,7 @@ func (am *DefaultAccountManager) DeleteGroup(ctx context.Context, accountId, use
 
 // ListGroups objects of the peers
 func (am *DefaultAccountManager) ListGroups(ctx context.Context, accountID string) ([]*nbgroup.Group, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -377,7 +377,7 @@ func (am *DefaultAccountManager) ListGroups(ctx context.Context, accountID strin
 
 // GroupAddPeer appends peer to the group
 func (am *DefaultAccountManager) GroupAddPeer(ctx context.Context, accountID, groupID, peerID string) error {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -413,7 +413,7 @@ func (am *DefaultAccountManager) GroupAddPeer(ctx context.Context, accountID, gr
 
 // GroupDeletePeer removes peer from the group
 func (am *DefaultAccountManager) GroupDeletePeer(ctx context.Context, accountID, groupID, peerID string) error {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
diff --git a/management/server/grpcserver.go b/management/server/grpcserver.go
index 170e72dd..f71a45d9 100644
--- a/management/server/grpcserver.go
+++ b/management/server/grpcserver.go
@@ -156,7 +156,7 @@ func (s *GRPCServer) Sync(req *proto.EncryptedMessage, srv proto.ManagementServi
 		log.WithContext(ctx).Tracef("peer system meta has to be provided on sync. Peer %s, remote addr %s", peerKey.String(), realIP)
 	}
 
-	peer, netMap, postureChecks, err := s.accountManager.SyncAndMarkPeer(ctx, peerKey.String(), extractPeerMeta(ctx, syncReq.GetMeta()), realIP)
+	peer, netMap, postureChecks, err := s.accountManager.SyncAndMarkPeer(ctx, accountID, peerKey.String(), extractPeerMeta(ctx, syncReq.GetMeta()), realIP)
 	if err != nil {
 		return mapError(ctx, err)
 	}
@@ -179,11 +179,11 @@ func (s *GRPCServer) Sync(req *proto.EncryptedMessage, srv proto.ManagementServi
 		s.appMetrics.GRPCMetrics().CountSyncRequestDuration(time.Since(reqStart))
 	}
 
-	return s.handleUpdates(ctx, peerKey, peer, updates, srv)
+	return s.handleUpdates(ctx, accountID, peerKey, peer, updates, srv)
 }
 
 // handleUpdates sends updates to the connected peer until the updates channel is closed.
-func (s *GRPCServer) handleUpdates(ctx context.Context, peerKey wgtypes.Key, peer *nbpeer.Peer, updates chan *UpdateMessage, srv proto.ManagementService_SyncServer) error {
+func (s *GRPCServer) handleUpdates(ctx context.Context, accountID string, peerKey wgtypes.Key, peer *nbpeer.Peer, updates chan *UpdateMessage, srv proto.ManagementService_SyncServer) error {
 	for {
 		select {
 		// condition when there are some updates
@@ -194,12 +194,12 @@ func (s *GRPCServer) handleUpdates(ctx context.Context, peerKey wgtypes.Key, pee
 
 			if !open {
 				log.WithContext(ctx).Debugf("updates channel for peer %s was closed", peerKey.String())
-				s.cancelPeerRoutines(ctx, peer)
+				s.cancelPeerRoutines(ctx, accountID, peer)
 				return nil
 			}
 			log.WithContext(ctx).Debugf("received an update for peer %s", peerKey.String())
 
-			if err := s.sendUpdate(ctx, peerKey, peer, update, srv); err != nil {
+			if err := s.sendUpdate(ctx, accountID, peerKey, peer, update, srv); err != nil {
 				return err
 			}
 
@@ -207,7 +207,7 @@ func (s *GRPCServer) handleUpdates(ctx context.Context, peerKey wgtypes.Key, pee
 		case <-srv.Context().Done():
 			// happens when connection drops, e.g. client disconnects
 			log.WithContext(ctx).Debugf("stream of peer %s has been closed", peerKey.String())
-			s.cancelPeerRoutines(ctx, peer)
+			s.cancelPeerRoutines(ctx, accountID, peer)
 			return srv.Context().Err()
 		}
 	}
@@ -215,10 +215,10 @@ func (s *GRPCServer) handleUpdates(ctx context.Context, peerKey wgtypes.Key, pee
 
 // sendUpdate encrypts the update message using the peer key and the server's wireguard key,
 // then sends the encrypted message to the connected peer via the sync server.
-func (s *GRPCServer) sendUpdate(ctx context.Context, peerKey wgtypes.Key, peer *nbpeer.Peer, update *UpdateMessage, srv proto.ManagementService_SyncServer) error {
+func (s *GRPCServer) sendUpdate(ctx context.Context, accountID string, peerKey wgtypes.Key, peer *nbpeer.Peer, update *UpdateMessage, srv proto.ManagementService_SyncServer) error {
 	encryptedResp, err := encryption.EncryptMessage(peerKey, s.wgKey, update.Update)
 	if err != nil {
-		s.cancelPeerRoutines(ctx, peer)
+		s.cancelPeerRoutines(ctx, accountID, peer)
 		return status.Errorf(codes.Internal, "failed processing update message")
 	}
 	err = srv.SendMsg(&proto.EncryptedMessage{
@@ -226,17 +226,17 @@ func (s *GRPCServer) sendUpdate(ctx context.Context, peerKey wgtypes.Key, peer *
 		Body:     encryptedResp,
 	})
 	if err != nil {
-		s.cancelPeerRoutines(ctx, peer)
+		s.cancelPeerRoutines(ctx, accountID, peer)
 		return status.Errorf(codes.Internal, "failed sending update message")
 	}
 	log.WithContext(ctx).Debugf("sent an update to peer %s", peerKey.String())
 	return nil
 }
 
-func (s *GRPCServer) cancelPeerRoutines(ctx context.Context, peer *nbpeer.Peer) {
+func (s *GRPCServer) cancelPeerRoutines(ctx context.Context, accountID string, peer *nbpeer.Peer) {
 	s.peersUpdateManager.CloseChannel(ctx, peer.ID)
 	s.turnCredentialsManager.CancelRefresh(peer.ID)
-	_ = s.accountManager.CancelPeerRoutines(ctx, peer)
+	_ = s.accountManager.OnPeerDisconnected(ctx, accountID, peer.Key)
 	s.ephemeralManager.OnPeerDisconnected(ctx, peer)
 }
 
diff --git a/management/server/integrated_validator.go b/management/server/integrated_validator.go
index 05537ada..99e6b204 100644
--- a/management/server/integrated_validator.go
+++ b/management/server/integrated_validator.go
@@ -32,7 +32,7 @@ func (am *DefaultAccountManager) UpdateIntegratedValidatorGroups(ctx context.Con
 		return errors.New("invalid groups")
 	}
 
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	a, err := am.Store.GetAccountByUser(ctx, userID)
diff --git a/management/server/mock_server/account_mock.go b/management/server/mock_server/account_mock.go
index 25bcdfce..a66bdee2 100644
--- a/management/server/mock_server/account_mock.go
+++ b/management/server/mock_server/account_mock.go
@@ -31,7 +31,7 @@ type MockAccountManager struct {
 	ListUsersFunc                       func(ctx context.Context, accountID string) ([]*server.User, error)
 	GetPeersFunc                        func(ctx context.Context, accountID, userID string) ([]*nbpeer.Peer, error)
 	MarkPeerConnectedFunc               func(ctx context.Context, peerKey string, connected bool, realIP net.IP) error
-	SyncAndMarkPeerFunc                 func(ctx context.Context, peerPubKey string, meta nbpeer.PeerSystemMeta, realIP net.IP) (*nbpeer.Peer, *server.NetworkMap, []*posture.Checks, error)
+	SyncAndMarkPeerFunc                 func(ctx context.Context, accountID string, peerPubKey string, meta nbpeer.PeerSystemMeta, realIP net.IP) (*nbpeer.Peer, *server.NetworkMap, []*posture.Checks, error)
 	DeletePeerFunc                      func(ctx context.Context, accountID, peerKey, userID string) error
 	GetNetworkMapFunc                   func(ctx context.Context, peerKey string) (*server.NetworkMap, error)
 	GetPeerNetworkFunc                  func(ctx context.Context, peerKey string) (*server.Network, error)
@@ -105,14 +105,14 @@ type MockAccountManager struct {
 	GetAccountIDForPeerKeyFunc          func(ctx context.Context, peerKey string) (string, error)
 }
 
-func (am *MockAccountManager) SyncAndMarkPeer(ctx context.Context, peerPubKey string, meta nbpeer.PeerSystemMeta, realIP net.IP) (*nbpeer.Peer, *server.NetworkMap, []*posture.Checks, error) {
+func (am *MockAccountManager) SyncAndMarkPeer(ctx context.Context, accountID string, peerPubKey string, meta nbpeer.PeerSystemMeta, realIP net.IP) (*nbpeer.Peer, *server.NetworkMap, []*posture.Checks, error) {
 	if am.SyncAndMarkPeerFunc != nil {
-		return am.SyncAndMarkPeerFunc(ctx, peerPubKey, meta, realIP)
+		return am.SyncAndMarkPeerFunc(ctx, accountID, peerPubKey, meta, realIP)
 	}
 	return nil, nil, nil, status.Errorf(codes.Unimplemented, "method MarkPeerConnected is not implemented")
 }
 
-func (am *MockAccountManager) CancelPeerRoutines(_ context.Context, peer *nbpeer.Peer) error {
+func (am *MockAccountManager) OnPeerDisconnected(_ context.Context, accountID string, peerPubKey string) error {
 	// TODO implement me
 	panic("implement me")
 }
diff --git a/management/server/nameserver.go b/management/server/nameserver.go
index f8d644de..636f7cfe 100644
--- a/management/server/nameserver.go
+++ b/management/server/nameserver.go
@@ -20,7 +20,7 @@ const domainPattern = `^(?i)[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,}$`
 // GetNameServerGroup gets a nameserver group object from account and nameserver group IDs
 func (am *DefaultAccountManager) GetNameServerGroup(ctx context.Context, accountID, userID, nsGroupID string) (*nbdns.NameServerGroup, error) {
 
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -48,7 +48,7 @@ func (am *DefaultAccountManager) GetNameServerGroup(ctx context.Context, account
 // CreateNameServerGroup creates and saves a new nameserver group
 func (am *DefaultAccountManager) CreateNameServerGroup(ctx context.Context, accountID string, name, description string, nameServerList []nbdns.NameServer, groups []string, primary bool, domains []string, enabled bool, userID string, searchDomainEnabled bool) (*nbdns.NameServerGroup, error) {
 
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -95,7 +95,7 @@ func (am *DefaultAccountManager) CreateNameServerGroup(ctx context.Context, acco
 // SaveNameServerGroup saves nameserver group
 func (am *DefaultAccountManager) SaveNameServerGroup(ctx context.Context, accountID, userID string, nsGroupToSave *nbdns.NameServerGroup) error {
 
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	if nsGroupToSave == nil {
@@ -130,7 +130,7 @@ func (am *DefaultAccountManager) SaveNameServerGroup(ctx context.Context, accoun
 // DeleteNameServerGroup deletes nameserver group with nsGroupID
 func (am *DefaultAccountManager) DeleteNameServerGroup(ctx context.Context, accountID, nsGroupID, userID string) error {
 
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -160,7 +160,7 @@ func (am *DefaultAccountManager) DeleteNameServerGroup(ctx context.Context, acco
 // ListNameServerGroups returns a list of nameserver groups from account
 func (am *DefaultAccountManager) ListNameServerGroups(ctx context.Context, accountID string, userID string) ([]*nbdns.NameServerGroup, error) {
 
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
diff --git a/management/server/peer.go b/management/server/peer.go
index a740067a..998a9e53 100644
--- a/management/server/peer.go
+++ b/management/server/peer.go
@@ -150,7 +150,7 @@ func (am *DefaultAccountManager) MarkPeerConnected(ctx context.Context, peerPubK
 
 // UpdatePeer updates peer. Only Peer.Name, Peer.SSHEnabled, and Peer.LoginExpirationEnabled can be updated.
 func (am *DefaultAccountManager) UpdatePeer(ctx context.Context, accountID, userID string, update *nbpeer.Peer) (*nbpeer.Peer, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -272,7 +272,7 @@ func (am *DefaultAccountManager) deletePeers(ctx context.Context, account *Accou
 
 // DeletePeer removes peer from the account by its IP
 func (am *DefaultAccountManager) DeletePeer(ctx context.Context, accountID, peerID, userID string) error {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -356,7 +356,7 @@ func (am *DefaultAccountManager) AddPeer(ctx context.Context, setupKey, userID s
 		return nil, nil, nil, status.Errorf(status.NotFound, "failed adding new peer: account not found")
 	}
 
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer func() {
 		if unlock != nil {
 			unlock()
@@ -380,7 +380,7 @@ func (am *DefaultAccountManager) AddPeer(ctx context.Context, setupKey, userID s
 	}
 
 	// This is a handling for the case when the same machine (with the same WireGuard pub key) tries to register twice.
-	// Such case is possible when AddPeer function takes long time to finish after AcquireAccountWriteLock (e.g., database is slow)
+	// Such case is possible when AddPeer function takes long time to finish after AcquireWriteLockByUID (e.g., database is slow)
 	// and the peer disconnects with a timeout and tries to register again.
 	// We just check if this machine has been registered before and reject the second registration.
 	// The connecting peer should be able to recover with a retry.
@@ -620,7 +620,7 @@ func (am *DefaultAccountManager) LoginPeer(ctx context.Context, login PeerLogin)
 		}
 	}
 
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer func() {
 		if unlock != nil {
 			unlock()
@@ -811,7 +811,7 @@ func (am *DefaultAccountManager) UpdatePeerSSHKey(ctx context.Context, peerID st
 		return err
 	}
 
-	unlock := am.Store.AcquireAccountWriteLock(ctx, account.Id)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, account.Id)
 	defer unlock()
 
 	// ensure that we consider modification happened meanwhile (because we were outside the account lock when we fetched the account)
@@ -846,7 +846,7 @@ func (am *DefaultAccountManager) UpdatePeerSSHKey(ctx context.Context, peerID st
 
 // GetPeer for a given accountID, peerID and userID error if not found.
 func (am *DefaultAccountManager) GetPeer(ctx context.Context, accountID, peerID, userID string) (*nbpeer.Peer, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
diff --git a/management/server/policy.go b/management/server/policy.go
index a70d7f0e..30614ed2 100644
--- a/management/server/policy.go
+++ b/management/server/policy.go
@@ -315,7 +315,7 @@ func (a *Account) connResourcesGenerator(ctx context.Context) (func(*PolicyRule,
 
 // GetPolicy from the store
 func (am *DefaultAccountManager) GetPolicy(ctx context.Context, accountID, policyID, userID string) (*Policy, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -343,7 +343,7 @@ func (am *DefaultAccountManager) GetPolicy(ctx context.Context, accountID, polic
 
 // SavePolicy in the store
 func (am *DefaultAccountManager) SavePolicy(ctx context.Context, accountID, userID string, policy *Policy) error {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -371,7 +371,7 @@ func (am *DefaultAccountManager) SavePolicy(ctx context.Context, accountID, user
 
 // DeletePolicy from the store
 func (am *DefaultAccountManager) DeletePolicy(ctx context.Context, accountID, policyID, userID string) error {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -398,7 +398,7 @@ func (am *DefaultAccountManager) DeletePolicy(ctx context.Context, accountID, po
 
 // ListPolicies from the store
 func (am *DefaultAccountManager) ListPolicies(ctx context.Context, accountID, userID string) ([]*Policy, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
diff --git a/management/server/posture_checks.go b/management/server/posture_checks.go
index 851d4d31..4a7c9755 100644
--- a/management/server/posture_checks.go
+++ b/management/server/posture_checks.go
@@ -15,7 +15,7 @@ const (
 )
 
 func (am *DefaultAccountManager) GetPostureChecks(ctx context.Context, accountID, postureChecksID, userID string) (*posture.Checks, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -42,7 +42,7 @@ func (am *DefaultAccountManager) GetPostureChecks(ctx context.Context, accountID
 }
 
 func (am *DefaultAccountManager) SavePostureChecks(ctx context.Context, accountID, userID string, postureChecks *posture.Checks) error {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -89,7 +89,7 @@ func (am *DefaultAccountManager) SavePostureChecks(ctx context.Context, accountI
 }
 
 func (am *DefaultAccountManager) DeletePostureChecks(ctx context.Context, accountID, postureChecksID, userID string) error {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -121,7 +121,7 @@ func (am *DefaultAccountManager) DeletePostureChecks(ctx context.Context, accoun
 }
 
 func (am *DefaultAccountManager) ListPostureChecks(ctx context.Context, accountID, userID string) ([]*posture.Checks, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
diff --git a/management/server/route.go b/management/server/route.go
index 6db00a25..064f3c10 100644
--- a/management/server/route.go
+++ b/management/server/route.go
@@ -17,7 +17,7 @@ import (
 
 // GetRoute gets a route object from account and route IDs
 func (am *DefaultAccountManager) GetRoute(ctx context.Context, accountID string, routeID route.ID, userID string) (*route.Route, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -126,7 +126,7 @@ func getRouteDescriptor(prefix netip.Prefix, domains domain.List) string {
 
 // CreateRoute creates and saves a new route
 func (am *DefaultAccountManager) CreateRoute(ctx context.Context, accountID string, prefix netip.Prefix, networkType route.NetworkType, domains domain.List, peerID string, peerGroupIDs []string, description string, netID route.NetID, masquerade bool, metric int, groups []string, enabled bool, userID string, keepRoute bool) (*route.Route, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -214,7 +214,7 @@ func (am *DefaultAccountManager) CreateRoute(ctx context.Context, accountID stri
 
 // SaveRoute saves route
 func (am *DefaultAccountManager) SaveRoute(ctx context.Context, accountID, userID string, routeToSave *route.Route) error {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	if routeToSave == nil {
@@ -283,7 +283,7 @@ func (am *DefaultAccountManager) SaveRoute(ctx context.Context, accountID, userI
 
 // DeleteRoute deletes route with routeID
 func (am *DefaultAccountManager) DeleteRoute(ctx context.Context, accountID string, routeID route.ID, userID string) error {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -311,7 +311,7 @@ func (am *DefaultAccountManager) DeleteRoute(ctx context.Context, accountID stri
 
 // ListRoutes returns a list of routes from account
 func (am *DefaultAccountManager) ListRoutes(ctx context.Context, accountID, userID string) ([]*route.Route, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
diff --git a/management/server/setupkey.go b/management/server/setupkey.go
index dcaee357..8ef91755 100644
--- a/management/server/setupkey.go
+++ b/management/server/setupkey.go
@@ -210,7 +210,7 @@ func Hash(s string) uint32 {
 // and adds it to the specified account. A list of autoGroups IDs can be empty.
 func (am *DefaultAccountManager) CreateSetupKey(ctx context.Context, accountID string, keyName string, keyType SetupKeyType,
 	expiresIn time.Duration, autoGroups []string, usageLimit int, userID string, ephemeral bool) (*SetupKey, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	keyDuration := DefaultSetupKeyDuration
@@ -256,7 +256,7 @@ func (am *DefaultAccountManager) CreateSetupKey(ctx context.Context, accountID s
 // (e.g. the key itself, creation date, ID, etc).
 // These properties are overwritten: Name, AutoGroups, Revoked. The rest is copied from the existing key.
 func (am *DefaultAccountManager) SaveSetupKey(ctx context.Context, accountID string, keyToSave *SetupKey, userID string) (*SetupKey, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	if keyToSave == nil {
@@ -328,7 +328,7 @@ func (am *DefaultAccountManager) SaveSetupKey(ctx context.Context, accountID str
 
 // ListSetupKeys returns a list of all setup keys of the account
 func (am *DefaultAccountManager) ListSetupKeys(ctx context.Context, accountID, userID string) ([]*SetupKey, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 	account, err := am.Store.GetAccount(ctx, accountID)
 	if err != nil {
@@ -360,7 +360,7 @@ func (am *DefaultAccountManager) ListSetupKeys(ctx context.Context, accountID, u
 
 // GetSetupKey looks up a SetupKey by KeyID, returns NotFound error if not found.
 func (am *DefaultAccountManager) GetSetupKey(ctx context.Context, accountID, userID, keyID string) (*SetupKey, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
diff --git a/management/server/sql_store.go b/management/server/sql_store.go
index 7648538c..c44ab7f0 100644
--- a/management/server/sql_store.go
+++ b/management/server/sql_store.go
@@ -40,7 +40,7 @@ const (
 // SqlStore represents an account storage backed by a Sql DB persisted to disk
 type SqlStore struct {
 	db                *gorm.DB
-	accountLocks      sync.Map
+	resourceLocks     sync.Map
 	globalAccountLock sync.Mutex
 	metrics           telemetry.AppMetrics
 	installationPK    int
@@ -98,33 +98,35 @@ func (s *SqlStore) AcquireGlobalLock(ctx context.Context) (unlock func()) {
 	return unlock
 }
 
-func (s *SqlStore) AcquireAccountWriteLock(ctx context.Context, accountID string) (unlock func()) {
-	log.WithContext(ctx).Tracef("acquiring write lock for account %s", accountID)
+// AcquireWriteLockByUID acquires an ID lock for writing to a resource and returns a function that releases the lock
+func (s *SqlStore) AcquireWriteLockByUID(ctx context.Context, uniqueID string) (unlock func()) {
+	log.WithContext(ctx).Tracef("acquiring write lock for ID %s", uniqueID)
 
 	start := time.Now()
-	value, _ := s.accountLocks.LoadOrStore(accountID, &sync.RWMutex{})
+	value, _ := s.resourceLocks.LoadOrStore(uniqueID, &sync.RWMutex{})
 	mtx := value.(*sync.RWMutex)
 	mtx.Lock()
 
 	unlock = func() {
 		mtx.Unlock()
-		log.WithContext(ctx).Tracef("released write lock for account %s in %v", accountID, time.Since(start))
+		log.WithContext(ctx).Tracef("released write lock for ID %s in %v", uniqueID, time.Since(start))
 	}
 
 	return unlock
 }
 
-func (s *SqlStore) AcquireAccountReadLock(ctx context.Context, accountID string) (unlock func()) {
-	log.WithContext(ctx).Tracef("acquiring read lock for account %s", accountID)
+// AcquireReadLockByUID acquires an ID lock for writing to a resource and returns a function that releases the lock
+func (s *SqlStore) AcquireReadLockByUID(ctx context.Context, uniqueID string) (unlock func()) {
+	log.WithContext(ctx).Tracef("acquiring read lock for ID %s", uniqueID)
 
 	start := time.Now()
-	value, _ := s.accountLocks.LoadOrStore(accountID, &sync.RWMutex{})
+	value, _ := s.resourceLocks.LoadOrStore(uniqueID, &sync.RWMutex{})
 	mtx := value.(*sync.RWMutex)
 	mtx.RLock()
 
 	unlock = func() {
 		mtx.RUnlock()
-		log.WithContext(ctx).Tracef("released read lock for account %s in %v", accountID, time.Since(start))
+		log.WithContext(ctx).Tracef("released read lock for ID %s in %v", uniqueID, time.Since(start))
 	}
 
 	return unlock
diff --git a/management/server/store.go b/management/server/store.go
index 15a419c7..864871c8 100644
--- a/management/server/store.go
+++ b/management/server/store.go
@@ -49,10 +49,10 @@ type Store interface {
 	DeleteTokenID2UserIDIndex(tokenID string) error
 	GetInstallationID() string
 	SaveInstallationID(ctx context.Context, ID string) error
-	// AcquireAccountWriteLock should attempt to acquire account lock for write purposes and return a function that releases the lock
-	AcquireAccountWriteLock(ctx context.Context, accountID string) func()
-	// AcquireAccountReadLock should attempt to acquire account lock for read purposes and return a function that releases the lock
-	AcquireAccountReadLock(ctx context.Context, accountID string) func()
+	// AcquireWriteLockByUID should attempt to acquire a lock for write purposes and return a function that releases the lock
+	AcquireWriteLockByUID(ctx context.Context, uniqueID string) func()
+	// AcquireReadLockByUID should attempt to acquire lock for read purposes and return a function that releases the lock
+	AcquireReadLockByUID(ctx context.Context, uniqueID string) func()
 	// AcquireGlobalLock should attempt to acquire a global lock and return a function that releases the lock
 	AcquireGlobalLock(ctx context.Context) func()
 	SavePeer(ctx context.Context, accountID string, peer *nbpeer.Peer) error
diff --git a/management/server/user.go b/management/server/user.go
index 65b5c787..b8afcda3 100644
--- a/management/server/user.go
+++ b/management/server/user.go
@@ -211,7 +211,7 @@ func NewOwnerUser(id string) *User {
 
 // createServiceUser creates a new service user under the given account.
 func (am *DefaultAccountManager) createServiceUser(ctx context.Context, accountID string, initiatorUserID string, role UserRole, serviceUserName string, nonDeletable bool, autoGroups []string) (*UserInfo, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -267,7 +267,7 @@ func (am *DefaultAccountManager) CreateUser(ctx context.Context, accountID, user
 
 // inviteNewUser Invites a USer to a given account and creates reference in datastore
 func (am *DefaultAccountManager) inviteNewUser(ctx context.Context, accountID, userID string, invite *UserInfo) (*UserInfo, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	if am.idpManager == nil {
@@ -368,7 +368,7 @@ func (am *DefaultAccountManager) GetUser(ctx context.Context, claims jwtclaims.A
 		return nil, fmt.Errorf("failed to get account with token claims %v", err)
 	}
 
-	unlock := am.Store.AcquireAccountWriteLock(ctx, account.Id)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, account.Id)
 	defer unlock()
 
 	account, err = am.Store.GetAccount(ctx, account.Id)
@@ -401,7 +401,7 @@ func (am *DefaultAccountManager) GetUser(ctx context.Context, claims jwtclaims.A
 // ListUsers returns lists of all users under the account.
 // It doesn't populate user information such as email or name.
 func (am *DefaultAccountManager) ListUsers(ctx context.Context, accountID string) ([]*User, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -428,7 +428,7 @@ func (am *DefaultAccountManager) DeleteUser(ctx context.Context, accountID, init
 	if initiatorUserID == targetUserID {
 		return status.Errorf(status.InvalidArgument, "self deletion is not allowed")
 	}
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -538,7 +538,7 @@ func (am *DefaultAccountManager) deleteUserPeers(ctx context.Context, initiatorU
 
 // InviteUser resend invitations to users who haven't activated their accounts prior to the expiration period.
 func (am *DefaultAccountManager) InviteUser(ctx context.Context, accountID string, initiatorUserID string, targetUserID string) error {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	if am.idpManager == nil {
@@ -578,7 +578,7 @@ func (am *DefaultAccountManager) InviteUser(ctx context.Context, accountID strin
 
 // CreatePAT creates a new PAT for the given user
 func (am *DefaultAccountManager) CreatePAT(ctx context.Context, accountID string, initiatorUserID string, targetUserID string, tokenName string, expiresIn int) (*PersonalAccessTokenGenerated, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	if tokenName == "" {
@@ -628,7 +628,7 @@ func (am *DefaultAccountManager) CreatePAT(ctx context.Context, accountID string
 
 // DeletePAT deletes a specific PAT from a user
 func (am *DefaultAccountManager) DeletePAT(ctx context.Context, accountID string, initiatorUserID string, targetUserID string, tokenID string) error {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -678,7 +678,7 @@ func (am *DefaultAccountManager) DeletePAT(ctx context.Context, accountID string
 
 // GetPAT returns a specific PAT from a user
 func (am *DefaultAccountManager) GetPAT(ctx context.Context, accountID string, initiatorUserID string, targetUserID string, tokenID string) (*PersonalAccessToken, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -710,7 +710,7 @@ func (am *DefaultAccountManager) GetPAT(ctx context.Context, accountID string, i
 
 // GetAllPATs returns all PATs for a user
 func (am *DefaultAccountManager) GetAllPATs(ctx context.Context, accountID string, initiatorUserID string, targetUserID string) ([]*PersonalAccessToken, error) {
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	account, err := am.Store.GetAccount(ctx, accountID)
@@ -752,7 +752,7 @@ func (am *DefaultAccountManager) SaveOrAddUser(ctx context.Context, accountID, i
 		return nil, status.Errorf(status.InvalidArgument, "provided user update is nil")
 	}
 
-	unlock := am.Store.AcquireAccountWriteLock(ctx, accountID)
+	unlock := am.Store.AcquireWriteLockByUID(ctx, accountID)
 	defer unlock()
 
 	updatedUsers, err := am.SaveOrAddUsers(ctx, accountID, initiatorUserID, []*User{update}, addIfNotExists)
@@ -859,7 +859,7 @@ func (am *DefaultAccountManager) SaveOrAddUsers(ctx context.Context, accountID,
 	}
 
 	account.Network.IncSerial()
-	if err = am.Store.SaveUsers(account.Id, account.Users); err != nil {
+	if err = am.Store.SaveAccount(ctx, account); err != nil {
 		return nil, err
 	}
 



Test patch:
diff --git a/client/system/info_darwin_test.go b/client/system/info_darwin_test.go
index 94e0b9e5..5608bc77 100644
--- a/client/system/info_darwin_test.go
+++ b/client/system/info_darwin_test.go
@@ -1,11 +1,12 @@
 package system
 
 import (
-	log "github.com/sirupsen/logrus"
 	"testing"
+
+	log "github.com/sirupsen/logrus"
 )
 
-func Test_sysInfo(t *testing.T) {
+func Test_sysInfoMac(t *testing.T) {
 	t.Skip("skipping darwin test")
 	serialNum, prodName, manufacturer := sysInfo()
 	if serialNum == "" {
diff --git a/client/system/sysinfo_linux_test.go b/client/system/sysinfo_linux_test.go
new file mode 100644
index 00000000..f6a0b705
--- /dev/null
+++ b/client/system/sysinfo_linux_test.go
@@ -0,0 +1,198 @@
+package system
+
+import "testing"
+
+func Test_sysInfo(t *testing.T) {
+	tests := []struct {
+		name             string
+		sysInfo          SysInfo
+		wantSerialNum    string
+		wantProdName     string
+		wantManufacturer string
+	}{
+		{
+			name: "Test Case 1",
+			sysInfo: SysInfo{
+				ChassisSerial: "Default string",
+				ProductSerial: "Default string",
+				BoardSerial:   "M80-G8013200245",
+				ProductName:   "B650M-HDV/M.2",
+				BoardName:     "B650M-HDV/M.2",
+				ProductVendor: "ASRock",
+			},
+			wantSerialNum:    "Default string",
+			wantProdName:     "B650M-HDV/M.2",
+			wantManufacturer: "ASRock",
+		},
+		{
+			name: "Empty Chassis Serial",
+			sysInfo: SysInfo{
+				ChassisSerial: "",
+				ProductSerial: "Default string",
+				BoardSerial:   "M80-G8013200245",
+				ProductName:   "B650M-HDV/M.2",
+				BoardName:     "B650M-HDV/M.2",
+				ProductVendor: "ASRock",
+			},
+			wantSerialNum:    "Default string",
+			wantProdName:     "B650M-HDV/M.2",
+			wantManufacturer: "ASRock",
+		},
+		{
+			name: "Empty Chassis Serial",
+			sysInfo: SysInfo{
+				ChassisSerial: "",
+				ProductSerial: "Default string",
+				BoardSerial:   "M80-G8013200245",
+				ProductName:   "B650M-HDV/M.2",
+				BoardName:     "B650M-HDV/M.2",
+				ProductVendor: "ASRock",
+			},
+			wantSerialNum:    "Default string",
+			wantProdName:     "B650M-HDV/M.2",
+			wantManufacturer: "ASRock",
+		},
+		{
+			name: "Fallback to Product Serial",
+			sysInfo: SysInfo{
+				ChassisSerial: "Default string",
+				ProductSerial: "Product serial",
+				BoardSerial:   "M80-G8013200245",
+				ProductName:   "B650M-HDV/M.2",
+				BoardName:     "B650M-HDV/M.2",
+				ProductVendor: "ASRock",
+			},
+			wantSerialNum:    "Product serial",
+			wantProdName:     "B650M-HDV/M.2",
+			wantManufacturer: "ASRock",
+		},
+		{
+			name: "Fallback to Product Serial with default string",
+			sysInfo: SysInfo{
+				ChassisSerial: "Default string",
+				ProductSerial: "Default string",
+				BoardSerial:   "M80-G8013200245",
+				ProductName:   "B650M-HDV/M.2",
+				BoardName:     "B650M-HDV/M.2",
+				ProductVendor: "ASRock",
+			},
+			wantSerialNum:    "Default string",
+			wantProdName:     "B650M-HDV/M.2",
+			wantManufacturer: "ASRock",
+		},
+		{
+			name: "Non UTF-8 in Chassis Serial",
+			sysInfo: SysInfo{
+				ChassisSerial: "\x80",
+				ProductSerial: "Product serial",
+				BoardSerial:   "M80-G8013200245",
+				ProductName:   "B650M-HDV/M.2",
+				BoardName:     "B650M-HDV/M.2",
+				ProductVendor: "ASRock",
+			},
+			wantSerialNum:    "Product serial",
+			wantProdName:     "B650M-HDV/M.2",
+			wantManufacturer: "ASRock",
+		},
+		{
+			name: "Non UTF-8 in Chassis Serial and Product Serial",
+			sysInfo: SysInfo{
+				ChassisSerial: "\x80",
+				ProductSerial: "\x80",
+				BoardSerial:   "M80-G8013200245",
+				ProductName:   "B650M-HDV/M.2",
+				BoardName:     "B650M-HDV/M.2",
+				ProductVendor: "ASRock",
+			},
+			wantSerialNum:    "M80-G8013200245",
+			wantProdName:     "B650M-HDV/M.2",
+			wantManufacturer: "ASRock",
+		},
+		{
+			name: "Non UTF-8 in Chassis Serial and Product Serial and BoardSerial",
+			sysInfo: SysInfo{
+				ChassisSerial: "\x80",
+				ProductSerial: "\x80",
+				BoardSerial:   "\x80",
+				ProductName:   "B650M-HDV/M.2",
+				BoardName:     "B650M-HDV/M.2",
+				ProductVendor: "ASRock",
+			},
+			wantSerialNum:    "",
+			wantProdName:     "B650M-HDV/M.2",
+			wantManufacturer: "ASRock",
+		},
+
+		{
+			name: "Empty Product Name",
+			sysInfo: SysInfo{
+				ChassisSerial: "Default string",
+				ProductSerial: "Default string",
+				BoardSerial:   "M80-G8013200245",
+				ProductName:   "",
+				BoardName:     "boardname",
+				ProductVendor: "ASRock",
+			},
+			wantSerialNum:    "Default string",
+			wantProdName:     "boardname",
+			wantManufacturer: "ASRock",
+		},
+		{
+			name: "Invalid Product Name",
+			sysInfo: SysInfo{
+				ChassisSerial: "Default string",
+				ProductSerial: "Default string",
+				BoardSerial:   "M80-G8013200245",
+				ProductName:   "\x80",
+				BoardName:     "boardname",
+				ProductVendor: "ASRock",
+			},
+			wantSerialNum:    "Default string",
+			wantProdName:     "boardname",
+			wantManufacturer: "ASRock",
+		},
+		{
+			name: "Invalid BoardName Name",
+			sysInfo: SysInfo{
+				ChassisSerial: "Default string",
+				ProductSerial: "Default string",
+				BoardSerial:   "M80-G8013200245",
+				ProductName:   "\x80",
+				BoardName:     "\x80",
+				ProductVendor: "ASRock",
+			},
+			wantSerialNum:    "Default string",
+			wantProdName:     "",
+			wantManufacturer: "ASRock",
+		},
+		{
+			name: "Invalid chars",
+			sysInfo: SysInfo{
+				ChassisSerial: "\x80",
+				ProductSerial: "\x80",
+				BoardSerial:   "\x80",
+				ProductName:   "\x80",
+				BoardName:     "\x80",
+				ProductVendor: "\x80",
+			},
+			wantSerialNum:    "",
+			wantProdName:     "",
+			wantManufacturer: "",
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			gotSerialNum, gotProdName, gotManufacturer := sysInfo(tt.sysInfo)
+			if gotSerialNum != tt.wantSerialNum {
+				t.Errorf("sysInfo() gotSerialNum = %v, want %v", gotSerialNum, tt.wantSerialNum)
+			}
+			if gotProdName != tt.wantProdName {
+				t.Errorf("sysInfo() gotProdName = %v, want %v", gotProdName, tt.wantProdName)
+			}
+			if gotManufacturer != tt.wantManufacturer {
+				t.Errorf("sysInfo() gotManufacturer = %v, want %v", gotManufacturer, tt.wantManufacturer)
+			}
+		})
+	}
+}
diff --git a/management/server/management_proto_test.go b/management/server/management_proto_test.go
index e1f7787f..2c9d4394 100644
--- a/management/server/management_proto_test.go
+++ b/management/server/management_proto_test.go
@@ -2,6 +2,7 @@ package server
 
 import (
 	"context"
+	"fmt"
 	"net"
 	"os"
 	"path/filepath"
@@ -16,6 +17,7 @@ import (
 	"google.golang.org/grpc/keepalive"
 
 	"github.com/netbirdio/netbird/encryption"
+	"github.com/netbirdio/netbird/formatter"
 	mgmtProto "github.com/netbirdio/netbird/management/proto"
 	"github.com/netbirdio/netbird/management/server/activity"
 	"github.com/netbirdio/netbird/util"
@@ -83,7 +85,7 @@ func Test_SyncProtocol(t *testing.T) {
 	defer func() {
 		os.Remove(filepath.Join(dir, "store.json")) //nolint
 	}()
-	mgmtServer, mgmtAddr, err := startManagement(t, &Config{
+	mgmtServer, _, mgmtAddr, err := startManagement(t, &Config{
 		Stuns: []*Host{{
 			Proto: "udp",
 			URI:   "stun:stun.wiretrustee.com:3468",
@@ -399,32 +401,35 @@ func TestServer_GetDeviceAuthorizationFlow(t *testing.T) {
 	}
 }
 
-func startManagement(t *testing.T, config *Config) (*grpc.Server, string, error) {
+func startManagement(t *testing.T, config *Config) (*grpc.Server, *DefaultAccountManager, string, error) {
 	t.Helper()
 	lis, err := net.Listen("tcp", "localhost:0")
 	if err != nil {
-		return nil, "", err
+		return nil, nil, "", err
 	}
 	s := grpc.NewServer(grpc.KeepaliveEnforcementPolicy(kaep), grpc.KeepaliveParams(kasp))
 	store, cleanUp, err := NewTestStoreFromJson(context.Background(), config.Datadir)
 	if err != nil {
-		return nil, "", err
+		return nil, nil, "", err
 	}
 	t.Cleanup(cleanUp)
 
 	peersUpdateManager := NewPeersUpdateManager(nil)
 	eventStore := &activity.InMemoryEventStore{}
-	accountManager, err := BuildManager(context.Background(), store, peersUpdateManager, nil, "", "netbird.selfhosted",
+
+	ctx := context.WithValue(context.Background(), formatter.ExecutionContextKey, formatter.SystemSource) //nolint:staticcheck
+
+	accountManager, err := BuildManager(ctx, store, peersUpdateManager, nil, "", "netbird.selfhosted",
 		eventStore, nil, false, MocIntegratedValidator{})
 	if err != nil {
-		return nil, "", err
+		return nil, nil, "", err
 	}
 	turnManager := NewTimeBasedAuthSecretsManager(peersUpdateManager, config.TURNConfig)
 
 	ephemeralMgr := NewEphemeralManager(store, accountManager)
 	mgmtServer, err := NewServer(context.Background(), config, accountManager, peersUpdateManager, turnManager, nil, ephemeralMgr)
 	if err != nil {
-		return nil, "", err
+		return nil, nil, "", err
 	}
 	mgmtProto.RegisterManagementServiceServer(s, mgmtServer)
 
@@ -434,7 +439,7 @@ func startManagement(t *testing.T, config *Config) (*grpc.Server, string, error)
 		}
 	}()
 
-	return s, lis.Addr().String(), nil
+	return s, accountManager, lis.Addr().String(), nil
 }
 
 func createRawClient(addr string) (mgmtProto.ManagementServiceClient, *grpc.ClientConn, error) {
@@ -454,3 +459,165 @@ func createRawClient(addr string) (mgmtProto.ManagementServiceClient, *grpc.Clie
 
 	return mgmtProto.NewManagementServiceClient(conn), conn, nil
 }
+func Test_SyncStatusRace(t *testing.T) {
+	if os.Getenv("CI") == "true" && os.Getenv("NETBIRD_STORE_ENGINE") == "postgres" {
+		t.Skip("Skipping on CI and Postgres store")
+	}
+	for i := 0; i < 500; i++ {
+		t.Run(fmt.Sprintf("TestRun-%d", i), func(t *testing.T) {
+			testSyncStatusRace(t)
+		})
+	}
+}
+func testSyncStatusRace(t *testing.T) {
+	t.Helper()
+	dir := t.TempDir()
+	err := util.CopyFileContents("testdata/store_with_expired_peers.json", filepath.Join(dir, "store.json"))
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer func() {
+		os.Remove(filepath.Join(dir, "store.json")) //nolint
+	}()
+
+	mgmtServer, am, mgmtAddr, err := startManagement(t, &Config{
+		Stuns: []*Host{{
+			Proto: "udp",
+			URI:   "stun:stun.wiretrustee.com:3468",
+		}},
+		TURNConfig: &TURNConfig{
+			TimeBasedCredentials: false,
+			CredentialsTTL:       util.Duration{},
+			Secret:               "whatever",
+			Turns: []*Host{{
+				Proto: "udp",
+				URI:   "turn:stun.wiretrustee.com:3468",
+			}},
+		},
+		Signal: &Host{
+			Proto: "http",
+			URI:   "signal.wiretrustee.com:10000",
+		},
+		Datadir:    dir,
+		HttpConfig: nil,
+	})
+	if err != nil {
+		t.Fatal(err)
+		return
+	}
+	defer mgmtServer.GracefulStop()
+
+	client, clientConn, err := createRawClient(mgmtAddr)
+	if err != nil {
+		t.Fatal(err)
+		return
+	}
+
+	defer clientConn.Close()
+
+	// there are two peers already in the store, add two more
+	peers, err := registerPeers(2, client)
+	if err != nil {
+		t.Fatal(err)
+		return
+	}
+
+	serverKey, err := getServerKey(client)
+	if err != nil {
+		t.Fatal(err)
+		return
+	}
+
+	concurrentPeerKey2 := peers[1]
+	t.Log("Public key of concurrent peer: ", concurrentPeerKey2.PublicKey().String())
+
+	syncReq2 := &mgmtProto.SyncRequest{Meta: &mgmtProto.PeerSystemMeta{}}
+	message2, err := encryption.EncryptMessage(*serverKey, *concurrentPeerKey2, syncReq2)
+	if err != nil {
+		t.Fatal(err)
+		return
+	}
+
+	ctx2, cancelFunc2 := context.WithCancel(context.Background())
+
+	//client.
+	sync2, err := client.Sync(ctx2, &mgmtProto.EncryptedMessage{
+		WgPubKey: concurrentPeerKey2.PublicKey().String(),
+		Body:     message2,
+	})
+	if err != nil {
+		t.Fatal(err)
+		return
+	}
+
+	resp2 := &mgmtProto.EncryptedMessage{}
+	err = sync2.RecvMsg(resp2)
+	if err != nil {
+		t.Fatal(err)
+		return
+	}
+
+	peerWithInvalidStatus := peers[0]
+	t.Log("Public key of peer with invalid status: ", peerWithInvalidStatus.PublicKey().String())
+
+	syncReq := &mgmtProto.SyncRequest{Meta: &mgmtProto.PeerSystemMeta{}}
+	message, err := encryption.EncryptMessage(*serverKey, *peerWithInvalidStatus, syncReq)
+	if err != nil {
+		t.Fatal(err)
+		return
+	}
+
+	ctx, cancelFunc := context.WithCancel(context.Background())
+
+	//client.
+	sync, err := client.Sync(ctx, &mgmtProto.EncryptedMessage{
+		WgPubKey: peerWithInvalidStatus.PublicKey().String(),
+		Body:     message,
+	})
+	if err != nil {
+		t.Fatal(err)
+		return
+	}
+
+	// take the first registered peer as a base for the test. Total four.
+
+	resp := &mgmtProto.EncryptedMessage{}
+	err = sync.RecvMsg(resp)
+	if err != nil {
+		t.Fatal(err)
+		return
+	}
+
+	cancelFunc2()
+	time.Sleep(1 * time.Millisecond)
+	cancelFunc()
+	time.Sleep(10 * time.Millisecond)
+
+	ctx, cancelFunc = context.WithCancel(context.Background())
+	defer cancelFunc()
+	sync, err = client.Sync(ctx, &mgmtProto.EncryptedMessage{
+		WgPubKey: peerWithInvalidStatus.PublicKey().String(),
+		Body:     message,
+	})
+	if err != nil {
+		t.Fatal(err)
+		return
+	}
+
+	resp = &mgmtProto.EncryptedMessage{}
+	err = sync.RecvMsg(resp)
+	if err != nil {
+		t.Fatal(err)
+		return
+	}
+
+	time.Sleep(10 * time.Millisecond)
+	peer, err := am.Store.GetPeerByPeerPubKey(context.Background(), peerWithInvalidStatus.PublicKey().String())
+	if err != nil {
+		t.Fatal(err)
+		return
+	}
+	if !peer.Status.Connected {
+		t.Fatal("Peer should be connected")
+	}
+}