diff --git a/client.c b/client.c
index be9dccbf..c97df491 100644
--- a/client.c
+++ b/client.c
@@ -45,11 +45,13 @@ static enum {
 	CLIENT_EXIT_LOST_SERVER,
 	CLIENT_EXIT_EXITED,
 	CLIENT_EXIT_SERVER_EXITED,
+	CLIENT_EXIT_MESSAGE_PROVIDED
 } client_exitreason = CLIENT_EXIT_NONE;
 static int		 client_exitflag;
 static int		 client_exitval;
 static enum msgtype	 client_exittype;
 static const char	*client_exitsession;
+static char		*client_exitmessage;
 static const char	*client_execshell;
 static const char	*client_execcmd;
 static int		 client_attached;
@@ -207,6 +209,8 @@ client_exit_message(void)
 		return ("exited");
 	case CLIENT_EXIT_SERVER_EXITED:
 		return ("server exited");
+	case CLIENT_EXIT_MESSAGE_PROVIDED:
+		return (client_exitmessage);
 	}
 	return ("unknown reason");
 }
@@ -791,13 +795,38 @@ client_dispatch(struct imsg *imsg, __unused void *arg)
 		client_dispatch_wait(imsg);
 }
 
+/* Process an exit message. */
+static void
+client_dispatch_exit_message(char *data, size_t datalen)
+{
+	int	retval;
+
+	if (datalen < sizeof retval && datalen != 0)
+		fatalx("bad MSG_EXIT size");
+
+	if (datalen >= sizeof retval) {
+		memcpy(&retval, data, sizeof retval);
+		client_exitval = retval;
+	}
+
+	if (datalen > sizeof retval) {
+		datalen -= sizeof retval;
+		data += sizeof retval;
+
+		client_exitmessage = xmalloc(datalen);
+		memcpy(client_exitmessage, data, datalen);
+		client_exitmessage[datalen - 1] = '\0';
+
+		client_exitreason = CLIENT_EXIT_MESSAGE_PROVIDED;
+	}
+}
+
 /* Dispatch imsgs when in wait state (before MSG_READY). */
 static void
 client_dispatch_wait(struct imsg *imsg)
 {
 	char		*data;
 	ssize_t		 datalen;
-	int		 retval;
 	static int	 pledge_applied;
 
 	/*
@@ -820,12 +849,7 @@ client_dispatch_wait(struct imsg *imsg)
 	switch (imsg->hdr.type) {
 	case MSG_EXIT:
 	case MSG_SHUTDOWN:
-		if (datalen != sizeof retval && datalen != 0)
-			fatalx("bad MSG_EXIT size");
-		if (datalen == sizeof retval) {
-			memcpy(&retval, data, sizeof retval);
-			client_exitval = retval;
-		}
+		client_dispatch_exit_message(data, datalen);
 		client_exitflag = 1;
 		client_exit();
 		break;
@@ -916,11 +940,10 @@ client_dispatch_attached(struct imsg *imsg)
 		proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
 		break;
 	case MSG_EXIT:
-		if (datalen != 0 && datalen != sizeof (int))
-			fatalx("bad MSG_EXIT size");
-
+		client_dispatch_exit_message(data, datalen);
+		if (client_exitreason == CLIENT_EXIT_NONE)
+			client_exitreason = CLIENT_EXIT_EXITED;
 		proc_send(client_peer, MSG_EXITING, -1, NULL, 0);
-		client_exitreason = CLIENT_EXIT_EXITED;
 		break;
 	case MSG_EXITED:
 		if (datalen != 0)
diff --git a/control.c b/control.c
index 8ebb615e..140849e1 100644
--- a/control.c
+++ b/control.c
@@ -89,13 +89,16 @@ struct control_state {
 	struct bufferevent		*write_event;
 };
 
-/* Low watermark. */
+/* Low and high watermarks. */
 #define CONTROL_BUFFER_LOW 512
 #define CONTROL_BUFFER_HIGH 8192
 
 /* Minimum to write to each client. */
 #define CONTROL_WRITE_MINIMUM 32
 
+/* Maximum age for clients that are not using pause mode. */
+#define CONTROL_MAXIMUM_AGE 300000
+
 /* Flags to ignore client. */
 #define CONTROL_IGNORE_FLAGS \
 	(CLIENT_CONTROL_NOOUTPUT| \
@@ -306,6 +309,41 @@ control_write(struct client *c, const char *fmt, ...)
 	va_end(ap);
 }
 
+/* Check age for this pane. */
+static int
+control_check_age(struct client *c, struct window_pane *wp,
+    struct control_pane *cp)
+{
+	struct control_block	*cb;
+	uint64_t		 t, age;
+
+	cb = TAILQ_FIRST(&cp->blocks);
+	if (cb == NULL)
+		return (0);
+	t = get_timer();
+	if (cb->t >= t)
+		return (0);
+
+	age = t - cb->t;
+	log_debug("%s: %s: %%%u is %llu behind", __func__, c->name, wp->id,
+	    (unsigned long long)age);
+
+	if (c->flags & CLIENT_CONTROL_PAUSEAFTER) {
+		if (age < c->pause_age)
+			return (0);
+		cp->flags |= CONTROL_PANE_PAUSED;
+		control_discard_pane(c, cp);
+		control_write(c, "%%pause %%%u", wp->id);
+	} else {
+		if (age < CONTROL_MAXIMUM_AGE)
+			return (0);
+		c->exit_message = xstrdup("too far behind");
+		c->flags |= CLIENT_EXIT;
+		control_discard(c);
+	}
+	return (1);
+}
+
 /* Write output from a pane. */
 void
 control_write_output(struct client *c, struct window_pane *wp)
@@ -314,7 +352,6 @@ control_write_output(struct client *c, struct window_pane *wp)
 	struct control_pane	*cp;
 	struct control_block	*cb;
 	size_t			 new_size;
-	uint64_t		 t;
 
 	if (winlink_find_by_window(&c->session->windows, wp->window) == NULL)
 		return;
@@ -328,20 +365,8 @@ control_write_output(struct client *c, struct window_pane *wp)
 	cp = control_add_pane(c, wp);
 	if (cp->flags & (CONTROL_PANE_OFF|CONTROL_PANE_PAUSED))
 		goto ignore;
-	if (c->flags & CLIENT_CONTROL_PAUSEAFTER) {
-		cb = TAILQ_FIRST(&cp->blocks);
-		if (cb != NULL) {
-			t = get_timer();
-			log_debug("%s: %s: %%%u is %lld behind", __func__,
-			    c->name, wp->id, (long long)t - cb->t);
-			if (cb->t < t - c->pause_age) {
-				cp->flags |= CONTROL_PANE_PAUSED;
-				control_discard_pane(c, cp);
-				control_write(c, "%%pause %%%u", wp->id);
-				return;
-			}
-		}
-	}
+	if (control_check_age(c, wp, cp))
+		return;
 
 	window_pane_get_new_data(wp, &cp->queued, &new_size);
 	if (new_size == 0)
diff --git a/server-client.c b/server-client.c
index 89275caf..9e7adf55 100644
--- a/server-client.c
+++ b/server-client.c
@@ -57,9 +57,6 @@ static void	server_client_dispatch_read_data(struct client *,
 static void	server_client_dispatch_read_done(struct client *,
 		    struct imsg *);
 
-/* Maximum data allowed to be held for a pane for a control client. */
-#define SERVER_CLIENT_PANE_LIMIT 16777216
-
 /* Compare client windows. */
 static int
 server_client_window_cmp(struct client_window *cw1,
@@ -1528,10 +1525,6 @@ server_client_check_pane_buffer(struct window_pane *wp)
 		log_debug("%s: %s has %zu bytes used and %zu left for %%%u",
 		    __func__, c->name, wpo->used - wp->base_offset, new_size,
 		    wp->id);
-		if (new_size > SERVER_CLIENT_PANE_LIMIT) {
-			control_discard(c);
-			c->flags |= CLIENT_EXIT;
-		}
 		if (wpo->used < minimum)
 			minimum = wpo->used;
 	}
@@ -1766,6 +1759,8 @@ server_client_check_exit(struct client *c)
 {
 	struct client_file	*cf;
 	const char		*name = c->exit_session;
+	char			*data;
+	size_t			 size, msize;
 
 	if (c->flags & (CLIENT_DEAD|CLIENT_EXITED))
 		return;
@@ -1788,7 +1783,17 @@ server_client_check_exit(struct client *c)
 
 	switch (c->exit_type) {
 	case CLIENT_EXIT_RETURN:
-		proc_send(c->peer, MSG_EXIT, -1, &c->retval, sizeof c->retval);
+		if (c->exit_message != NULL) {
+			msize = strlen(c->exit_message) + 1;
+			size = (sizeof c->retval) + msize;
+		} else
+			size = (sizeof c->retval);
+		data = xmalloc(size);
+		memcpy(data, &c->retval, sizeof c->retval);
+		if (c->exit_message != NULL)
+			memcpy(data + sizeof c->retval, c->exit_message, msize);
+		proc_send(c->peer, MSG_EXIT, -1, data, size);
+		free(data);
 		break;
 	case CLIENT_EXIT_SHUTDOWN:
 		proc_send(c->peer, MSG_SHUTDOWN, -1, NULL, 0);
@@ -1798,6 +1803,7 @@ server_client_check_exit(struct client *c)
 		break;
 	}
 	free(c->exit_session);
+	free(c->exit_message);
 }
 
 /* Redraw timer callback. */
diff --git a/tmux.1 b/tmux.1
index 2200f193..1a3cde5d 100644
--- a/tmux.1
+++ b/tmux.1
@@ -5727,29 +5727,32 @@ When a
 client detaches, it prints a message.
 This may be one of:
 .Bl -tag -width Ds
-.It [detached (from session ...)]
+.It detached (from session ...)
 The client was detached normally.
-.It [detached and SIGHUP]
+.It detached and SIGHUP
 The client was detached and its parent sent the
 .Dv SIGHUP
 signal (for example with
 .Ic detach-client
 .Fl P ) .
-.It [lost tty]
+.It lost tty
 The client's
 .Xr tty 4
 or
 .Xr pty 4
 was unexpectedly destroyed.
-.It [terminated]
+.It terminated
 The client was killed with
 .Dv SIGTERM .
-.It [exited]
+.It too far behind
+The client is in control mode and became unable to keep up with the data from
+.Nm .
+.It exited
 The server exited when it had no sessions.
-.It [server exited]
+.It server exited
 The server exited when it received
 .Dv SIGTERM .
-.It [server exited unexpectedly]
+.It server exited unexpectedly
 The server crashed or otherwise exited without telling the client the reason.
 .El
 .Sh TERMINFO EXTENSIONS
diff --git a/tmux.h b/tmux.h
index df63321d..ee59b4b3 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1668,6 +1668,7 @@ struct client {
 	}		 exit_type;
 	enum msgtype	 exit_msgtype;
 	char		*exit_session;
+	char		*exit_message;
 
 	struct key_table *keytable;