=== apps/desktop/src/connect-server-sync.ts
@@ -140,7 +140,19 @@ export interface CreateConnectServerSyncArgs {
   clearIntervalFn?: (handle: unknown) => void;
 }
 
+/**
+ * Why the last sync produced no server list. `null` once a sync has succeeded.
+ * Surfaced in the Server menu so an empty list is distinguishable from an
+ * account that genuinely has no servers.
+ */
+export type ConnectServerSyncSkipReason =
+  | "no-credential"
+  | "unauthorized"
+  | "unavailable";
+
 export interface ConnectServerSync {
+  /** Why the last sync yielded no servers, or null after a successful sync. */
+  getSkipReason(): ConnectServerSyncSkipReason | null;
   /** Start the 10-minute background timer (unref'd so it does not keep the app alive). */
   start(): void;
   stop(): void;
@@ -180,6 +192,7 @@ export function createConnectServerSync(
   let lastSyncAttemptAt = 0;
   let inFlight: Promise<void> | null = null;
   let loggedFailure = false;
+  let skipReason: ConnectServerSyncSkipReason | null = null;
 
   /**
    * Prefer the local server: it holds the pairing secret and always reflects
@@ -189,19 +202,23 @@ export function createConnectServerSync(
   async function fetchServers(): Promise<ConnectListAccountServersResult | null> {
     const serverUrl = args.getLocalServerUrl();
     if (serverUrl !== null) {
+      skipReason = "unavailable";
       return fetchConnectAccountServers({
         serverUrl,
         fetchImpl: args.fetchImpl,
       });
     }
     const credential = args.getCredential();
     if (credential === null) {
+      skipReason = "no-credential";
       return null;
     }
     try {
+      skipReason = "unavailable";
       return await listAccountServers(credential, args.gateFetchImpl);
     } catch (error) {
       if (error instanceof ConnectListError && error.code === "unauthorized") {
+        skipReason = "unauthorized";
         args.onUnauthorized();
       }
       return null;
@@ -222,6 +239,7 @@ export function createConnectServerSync(
     }
 
     loggedFailure = false;
+    skipReason = null;
     args.onServers(selectTargetableConnectServers(result));
   }
 
@@ -274,6 +292,7 @@ export function createConnectServerSync(
   }
 
   return {
+    getSkipReason: () => skipReason,
     start,
     stop,
     onRuntimeReady,
=== apps/desktop/src/main.ts
@@ -671,8 +671,30 @@ function buildMenuServerItems(): Array<{
   return items;
 }
 
+/**
+ * The Server menu lists Connect servers only after a successful sync. When the
+ * sync could not run, an empty list otherwise looks identical to an account
+ * with no servers, so name the reason instead.
+ */
+function buildMenuServersNote(): string | null {
+  if (listMenuConnectServers().length > 0) {
+    return null;
+  }
+  switch (connectServerSync?.getSkipReason() ?? null) {
+    case "no-credential":
+      return "No Connect servers — sign in to bb Connect";
+    case "unauthorized":
+      return "No Connect servers — bb Connect sign-in expired";
+    case "unavailable":
+      return "No Connect servers — could not reach bb Connect";
+    default:
+      return null;
+  }
+}
+
 function installCurrentApplicationMenu(): void {
   installApplicationMenu({
+    serversNote: buildMenuServersNote(),
     accelerators: currentApplicationMenuAccelerators,
     isMac: process.platform === "darwin",
     createNewWindow() {
=== apps/desktop/src/menu.ts
@@ -45,6 +45,12 @@ export interface InstallApplicationMenuArgs {
   onServerMenuWillShow?: () => void;
   serverDaemonLogsMenuEnabled: boolean;
   servers: ApplicationMenuServerItem[];
+  /**
+   * Why no Connect servers are listed, when that is because the sync could not
+   * run rather than because the account has none. Rendered as a disabled item
+   * so the two cases are distinguishable.
+   */
+  serversNote?: string | null;
 }
 
 function createServerDaemonLogsMenuItems(
@@ -75,8 +81,13 @@ function createServerMenuItems(
       type: "radio" as const,
     }),
   );
+  const note: MenuItemConstructorOptions[] =
+    args.serversNote === undefined || args.serversNote === null
+      ? []
+      : [{ enabled: false, label: args.serversNote }];
   return [
     ...serverItems,
+    ...note,
     { type: "separator" },
     {
       label: SET_SERVER_URL_MENU_LABEL,
