conn: Optional[IrcConnection] = None
     _cls_conn: type[IrcConnection] = IrcConnection
     _expected_pong: str
-    _retry_connect_in_s: int = -1
+    _retry_connect_in_s: int
     _retry_connect_id: Optional[UUID] = None
+    _RETRY_CONNECT_IN_S_OFF = 0
 
     def __init__(self, conn_setup: IrcConnSetup, channels: set[str], **kwargs
                  ) -> None:
+        self._retry_connect_in_s = self._RETRY_CONNECT_IN_S_OFF
         self.client_id = conn_setup.hostname
         self._autojoins = channels
         super().__init__(client_id=self.client_id, **kwargs)
         # Do this in a thread, not to block flow of other (e.g. TUI) events.
         Thread(target=connect, daemon=True, args=(self,)).start()
 
+    @property
+    def _retry_connect_on(self) -> bool:
+        return self._retry_connect_in_s > self._RETRY_CONNECT_IN_S_OFF
+
     def _on_connecting_exception(self, e: IrcConnException) -> None:
         self.db.connection_state = f'failed to connect: {e}'
         if e.retry:
-            if not self._retry_connect_in_s > 0:
+            if not self._retry_connect_on:
                 self._retry_connect_in_s = 1
             self._delayed_retry_connect()
 
     def _on_connected(self) -> None:
         self._expected_pong = ''
-        self._retry_connect_in_s = -1
+        self._retry_connect_in_s = self._RETRY_CONNECT_IN_S_OFF
         self.db.connection_state = 'connected'
         self.caps.start_negotation()
         self.send('USER', self.db.user_wanted, '0', '*', self.db.realname)
         self.send('NICK', self.db.nick_wanted,)
 
     def _delayed_retry_connect(self) -> None:
-        def delayed_connect(self, wait_s: int, retry_connect_id: UUID
-                            ) -> None:
+        def delayed_connect(self, wait_s: int, retry_connect_id: UUID) -> None:
             sleep(wait_s)
             if self._retry_connect_id == retry_connect_id:
                 self._client_trigger('connect')
 
     def consider_retry(self) -> None:
         'Interpret .db.connection_state, on triggers set retry connect.'
-        if self._retry_connect_in_s > 0:
+        if self._retry_connect_on:
             return
         for _ in [re for re in _DISCONNECT_MSG_REGEXES_TO_RETRY_ON
                   if re_search(re, self.db.connection_state, re_IGNORECASE)]:
         if self.conn:
             self.conn.close()
         self.conn = None
-        if self._retry_connect_in_s > 0:
+        if self._retry_connect_on:
             self._delayed_retry_connect()
 
     def on_handled_loop_exception(self, e: IrcConnException) -> None:
 
         self._client_trigger('send_w_params_tuple', verb=verb, params=params)
 
     def cmd__disconnect(self, quit_msg: str = 'ircplom says bye') -> None:
-        'Send QUIT command to server.'
-        self._send_msg('QUIT', (quit_msg,))
+        'Ask to disconnect, or end auto-connect attempts if disconnected.'
+        self._client_trigger('disconnect', quit_msg=quit_msg)
 
     def cmd__reconnect(self) -> None:
         'Attempt reconnection.'
         elif self.send('PRIVMSG', chat_target, msg):
             self.db.messaging('').to(chat_target).privmsg = msg  # type: ignore
 
+    def disconnect(self, quit_msg: str) -> None:
+        'Send QUIT if connected, else end auto-connect attempts.'
+        if self.conn:
+            self.send('QUIT', quit_msg)
+            return
+        prefix = 'already disconnected'
+        if self._retry_connect_on:
+            self._retry_connect_id = None
+            self._tui_trigger('log', prefix_char=_LOG_PREFIX_SERVER,
+                              msg=f'{prefix}, stopped connecting attempts')
+        else:
+            self._tui_alert_trigger(f'{prefix} and not attempting connect')
+
     def reconnect(self) -> None:
         'Catch /reconnect, only initiate if not connected, else complain back.'
         if self.conn:
 
 # with TestingClient finally having reduced port to 10000, connecting works now
 insert conn : +1
 
-# test retry chain also started by in-connection timeout
+# check retry chain also started by in-connection timeout
 servermsg 0 timeout
 log 1 > PING :what's up?
 servermsg 0 timeout
 log 1 $ connection_state set to: []
 log , $ DISCONNECTED
 log 1 $ will retry connecting in 1 seconds
-insert conn : +1
+
+# check /disconnect aborts retry chain
+> /window 1
+> /disconnect
+log 1 $ already disconnected, stopped connecting attempts
+wait 1
 
 # on second server, check timed auto-retries don't activate after manual intervention
 > /connect baz.bar.foo:10003 foo:bar baz:foobarbazquux
 
 log 1 > CAP LS :302
 log 1 > USER baz 0 * :bar
 log 1 > NICK :foo
+× disconnecting
+insert isupport-clear : +1
+log 1 $ connection_state set to: []
+log , $ DISCONNECTED
 ×
 
 # to prepare, initiate connection
 log 1 > QUIT :ircplom says bye
 loggedservermsg 0 1 < ERROR :Closing link: (whatever@whatever.com) [Quit: ircplom says bye]
 log 1 $ connection_state set to: [Closing link: (whatever@whatever.com) [Quit: ircplom says bye]]
-insert isupport-clear : +1
-log 1 $ connection_state set to: []
-log , $ DISCONNECTED
+insert disconnecting : +1
 
 # fail to disconnect when already disconnected
 > /disconnect
-log 1 $ cannot send, connection seems closed
+log 1 $ already disconnected and not attempting connect
 
 # succeed to re-connect after disconnect
 > /reconnect
 insert connecting : +1
+
+# allow /disconnect outside connection for auto-connect stops
+loggedservermsg 0 1 < ERROR :Closing link: (Connection timed out)
+log 1 $ connection_state set to: [Closing link: (Connection timed out)]
+insert disconnecting : +1
+log 1 $ will retry connecting in 1 seconds
+> /disconnect
+log 1 $ already disconnected, stopped connecting attempts