diff --git a/SignalServiceKit/src/Devices/OWSDevice.h b/SignalServiceKit/src/Devices/OWSDevice.h
index e3b3f2259..b42e14b1b 100644
--- a/SignalServiceKit/src/Devices/OWSDevice.h
+++ b/SignalServiceKit/src/Devices/OWSDevice.h
@@ -17,6 +17,7 @@ extern uint32_t const OWSDevicePrimaryDeviceId;
 
 - (BOOL)mayHaveLinkedDevices:(YapDatabaseConnection *)dbConnection;
 - (void)setMayHaveLinkedDevices;
+- (void)clearMayHaveLinkedDevicesIfNotSet;
 
 - (BOOL)hasReceivedSyncMessageInLastSeconds:(NSTimeInterval)intervalSeconds;
 - (void)setHasReceivedSyncMessage;
diff --git a/SignalServiceKit/src/Devices/OWSDevice.m b/SignalServiceKit/src/Devices/OWSDevice.m
index f47d0c133..17d7ad708 100644
--- a/SignalServiceKit/src/Devices/OWSDevice.m
+++ b/SignalServiceKit/src/Devices/OWSDevice.m
@@ -19,9 +19,6 @@ NSString *const kTSStorageManager_MayHaveLinkedDevices = @"kTSStorageManager_May
 
 @interface OWSDeviceManager ()
 
-// This property should only be accessed while synchronized on self.
-@property (atomic, nullable) NSNumber *mayHaveLinkedDevicesCached;
-
 @property (atomic) NSDate *lastReceivedSyncMessage;
 
 @end
@@ -49,30 +46,34 @@ NSString *const kTSStorageManager_MayHaveLinkedDevices = @"kTSStorageManager_May
 {
     OWSAssert(dbConnection);
 
-    @synchronized(self)
-    {
-        if (!self.mayHaveLinkedDevicesCached) {
-            self.mayHaveLinkedDevicesCached = @([dbConnection boolForKey:kTSStorageManager_MayHaveLinkedDevices
-                                                            inCollection:kTSStorageManager_OWSDeviceCollection
-                                                            defaultValue:YES]);
-        }
+    return [dbConnection boolForKey:kTSStorageManager_MayHaveLinkedDevices
+                       inCollection:kTSStorageManager_OWSDeviceCollection
+                       defaultValue:YES];
+}
 
-        return [self.mayHaveLinkedDevicesCached boolValue];
-    }
+// In order to avoid skipping necessary sync messages, the default value
+// for mayHaveLinkedDevices is YES.  Once we've successfully sent a
+// sync message with no device messages (e.g. the service has confirmed
+// that we have no linked devices), we can set mayHaveLinkedDevices to NO
+// to avoid unnecessary message sends for sync messages until we learn
+// of a linked device (e.g. through the device linking UI or by receiving
+// a sync message, etc.).
+- (void)clearMayHaveLinkedDevicesIfNotSet
+{
+    // Note that we write async to avoid opening transactions within transactions.
+    [TSStorageManager.sharedManager.newDatabaseConnection
+        asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
+            if (![transaction objectForKey:kTSStorageManager_MayHaveLinkedDevices
+                              inCollection:kTSStorageManager_OWSDeviceCollection]) {
+                [transaction setObject:@(NO)
+                                forKey:kTSStorageManager_MayHaveLinkedDevices
+                          inCollection:kTSStorageManager_OWSDeviceCollection];
+            }
+        }];
 }
 
 - (void)setMayHaveLinkedDevices
 {
-    @synchronized(self)
-    {
-        if (self.mayHaveLinkedDevicesCached != nil && self.mayHaveLinkedDevicesCached.boolValue) {
-            // Skip redundant writes.
-            return;
-        }
-
-        self.mayHaveLinkedDevicesCached = @(YES);
-    }
-
     // Note that we write async to avoid opening transactions within transactions.
     [TSStorageManager.sharedManager.newDatabaseConnection
         asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
diff --git a/SignalServiceKit/src/Messages/OWSMessageSender.m b/SignalServiceKit/src/Messages/OWSMessageSender.m
index bbdb82ccf..94c589eb5 100644
--- a/SignalServiceKit/src/Messages/OWSMessageSender.m
+++ b/SignalServiceKit/src/Messages/OWSMessageSender.m
@@ -934,9 +934,10 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
     }
 
     NSString *localNumber = [TSAccountManager localNumber];
-    if ([localNumber isEqualToString:recipient.uniqueId]) {
+    BOOL isLocalNumber = [localNumber isEqualToString:recipient.uniqueId];
+    if (isLocalNumber) {
         OWSAssert([message isKindOfClass:[OWSOutgoingSyncMessage class]]);
-        // Messages send to the "local number" should be sync messages.
+        // Messages sent to the "local number" should be sync messages.
         //
         // We can skip sending sync messages if we know that we have no linked
         // devices. However, we need to be sure to handle the case where the
@@ -957,6 +958,11 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
         // 2. Check SignalRecipient's state.
         BOOL hasDeviceMessages = deviceMessages.count > 0;
 
+        DDLogInfo(@"%@ mayHaveLinkedDevices: %d, hasDeviceMessages: %d",
+            self.logTag,
+            mayHaveLinkedDevices,
+            hasDeviceMessages);
+
         if (!mayHaveLinkedDevices && !hasDeviceMessages) {
             DDLogInfo(@"%@ Ignoring sync message without secondary devices: %@", self.logTag, [message class]);
             OWSAssert([message isKindOfClass:[OWSOutgoingSyncMessage class]]);
@@ -982,13 +988,28 @@ NSString *const OWSMessageSenderRateLimitedException = @"RateLimitedException";
         OWSAssert(deviceMessages.count > 0);
     }
 
+    if (deviceMessages.count == 0) {
+        DDLogWarn(@"%@ Sending a message with no device messages.", self.logTag);
+    }
+
     TSSubmitMessageRequest *request = [[TSSubmitMessageRequest alloc] initWithRecipient:recipient.uniqueId
                                                                                messages:deviceMessages
                                                                                   relay:recipient.relay
                                                                               timeStamp:message.timestamp];
-
     [self.networkManager makeRequest:request
         success:^(NSURLSessionDataTask *task, id responseObject) {
+            if (isLocalNumber && deviceMessages.count == 0) {
+                DDLogInfo(@"%@ Sent a message with no device messages; clearing 'mayHaveLinkedDevices'.", self.logTag);
+                // In order to avoid skipping necessary sync messages, the default value
+                // for mayHaveLinkedDevices is YES.  Once we've successfully sent a
+                // sync message with no device messages (e.g. the service has confirmed
+                // that we have no linked devices), we can set mayHaveLinkedDevices to NO
+                // to avoid unnecessary message sends for sync messages until we learn
+                // of a linked device (e.g. through the device linking UI or by receiving
+                // a sync message, etc.).
+                [OWSDeviceManager.sharedManager clearMayHaveLinkedDevicesIfNotSet];
+            }
+
             dispatch_async([OWSDispatch sendingQueue], ^{
                 [recipient save];
                 [self handleMessageSentLocally:message];