diff --git a/cmd-command-prompt.c b/cmd-command-prompt.c
index dac334b2..e4954ddd 100644
--- a/cmd-command-prompt.c
+++ b/cmd-command-prompt.c
@@ -27,56 +27,112 @@
  * Prompt for command in client.
  */
 
-void	cmd_command_prompt_init(struct cmd *, int);
-int	cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *);
+void	 cmd_command_prompt_init(struct cmd *, int);
+int	 cmd_command_prompt_parse(struct cmd *, int, char **, char **);
+int	 cmd_command_prompt_exec(struct cmd *, struct cmd_ctx *);
+void	 cmd_command_prompt_free(struct cmd *);
+size_t	 cmd_command_prompt_print(struct cmd *, char *, size_t);
 
-int	cmd_command_prompt_callback(void *, const char *);
-void	cmd_command_prompt_free(void *);
+int	 cmd_command_prompt_callback(void *, const char *);
+void	 cmd_command_prompt_cfree(void *);
+char	*cmd_command_prompt_replace(char *, const char *, int);
 
 const struct cmd_entry cmd_command_prompt_entry = {
 	"command-prompt", NULL,
-	CMD_TARGET_CLIENT_USAGE " [template]",
-	CMD_ARG01, 0,
+	CMD_TARGET_CLIENT_USAGE " [-p prompts] [template]",
+	0, 0,
 	cmd_command_prompt_init,
-	cmd_target_parse,
+	cmd_command_prompt_parse,
 	cmd_command_prompt_exec,
-	cmd_target_free,
-	cmd_target_print
+	cmd_command_prompt_free,
+	cmd_command_prompt_print
 };
 
 struct cmd_command_prompt_data {
+	char	*prompts;
+	char	*target;
+	char	*template;
+};
+
+struct cmd_command_prompt_cdata {
 	struct client	*c;
+	char		*next_prompt;
+	char		*prompts;
 	char		*template;
+	int		 idx;
 };
 
 void
 cmd_command_prompt_init(struct cmd *self, int key)
 {
-	struct cmd_target_data	*data;
+	struct cmd_command_prompt_data	*data;
 
-	cmd_target_init(self, key);
-	data = self->data;
+	self->data = data = xmalloc(sizeof *data);
+	data->prompts = NULL;
+	data->target = NULL;
+	data->template = NULL;
 
 	switch (key) {
 	case ',':
-		data->arg = xstrdup("rename-window '%%'");
+		data->template = xstrdup("rename-window '%%'");
 		break;
 	case '.':
-		data->arg = xstrdup("move-window -t '%%'");
+		data->template = xstrdup("move-window -t '%%'");
 		break;
 	case 'f':
-		data->arg = xstrdup("find-window '%%'");
+		data->template = xstrdup("find-window '%%'");
 		break;
 	}
 }
 
+int
+cmd_command_prompt_parse(struct cmd *self, int argc, char **argv, char **cause)
+{
+	struct cmd_command_prompt_data	*data;
+	int				 opt;
+
+	self->entry->init(self, 0);
+	data = self->data;
+
+	while ((opt = getopt(argc, argv, "p:t:")) != -1) {
+		switch (opt) {
+		case 'p':
+			if (data->prompts == NULL)
+				data->prompts = xstrdup(optarg);
+			break;
+		case 't':
+			if (data->target == NULL)
+				data->target = xstrdup(optarg);
+			break;
+		default:
+			goto usage;
+		}
+	}
+	argc -= optind;
+	argv += optind;
+	if (argc != 0 && argc != 1)
+		goto usage;
+
+	if (argc == 1)
+		data->template = xstrdup(argv[0]);
+
+	return (0);
+
+usage:
+	xasprintf(cause, "usage: %s %s", self->entry->name, self->entry->usage);
+
+	self->entry->free(self);
+	return (-1);
+}
+
 int
 cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx)
 {
-	struct cmd_target_data		*data = self->data;
-	struct cmd_command_prompt_data	*cdata;
+	struct cmd_command_prompt_data	*data = self->data;
+	struct cmd_command_prompt_cdata	*cdata;
 	struct client			*c;
-	char				*hdr, *ptr;
+	char				*prompt, *ptr;
+	size_t				 n;
 
 	if ((c = cmd_find_client(ctx, data->target)) == NULL)
 		return (-1);
@@ -86,76 +142,100 @@ cmd_command_prompt_exec(struct cmd *self, struct cmd_ctx *ctx)
 
 	cdata = xmalloc(sizeof *cdata);
 	cdata->c = c;
-	if (data->arg != NULL) {
-		cdata->template = xstrdup(data->arg);
-		if ((ptr = strchr(data->arg, ' ')) == NULL)
-			ptr = strchr(data->arg, '\0');
-		xasprintf(&hdr, "(%.*s) ", (int) (ptr - data->arg), data->arg);
-	} else {
-		cdata->template = NULL;
-		hdr = xstrdup(":");
-	}
-	status_prompt_set(c, hdr,
-	    cmd_command_prompt_callback, cmd_command_prompt_free, cdata, 0);
-	xfree(hdr);
+	cdata->idx = 1;
+	cdata->next_prompt = NULL;
+	cdata->prompts = NULL;
+	cdata->template = NULL;
+
+	if (data->template != NULL)
+		cdata->template = xstrdup(data->template);
+	else
+		cdata->template = xstrdup("%1");
+	if (data->prompts != NULL)
+		cdata->prompts = xstrdup(data->prompts);
+	else if (data->template != NULL) {
+		n = strcspn(data->template, " ,");
+		xasprintf(&cdata->prompts, "(%.*s) ", (int) n, data->template);
+	} else
+		cdata->prompts = xstrdup(":");
+
+	cdata->next_prompt = cdata->prompts;
+	ptr = strsep(&cdata->next_prompt, ",");
+	if (data->prompts == NULL)
+		prompt = xstrdup(ptr);
+	else
+		xasprintf(&prompt, "%s ", ptr);
+	status_prompt_set(c, prompt, cmd_command_prompt_callback,
+	    cmd_command_prompt_cfree, cdata, 0);
+	xfree(prompt);
 
 	return (0);
 }
 
+void
+cmd_command_prompt_free(struct cmd *self)
+{
+	struct cmd_command_prompt_data	*data = self->data;
+
+	if (data->prompts != NULL)
+		xfree(data->prompts);
+	if (data->target != NULL)
+		xfree(data->target);
+	if (data->template != NULL)
+		xfree(data->template);
+	xfree(data);
+}
+
+size_t
+cmd_command_prompt_print(struct cmd *self, char *buf, size_t len)
+{
+	struct cmd_command_prompt_data	*data = self->data;
+	size_t				 off = 0;
+
+	off += xsnprintf(buf, len, "%s", self->entry->name);
+	if (data == NULL)
+		return (off);
+	if (off < len && data->prompts != NULL)
+		off += cmd_prarg(buf + off, len - off, " -p ", data->prompts);
+	if (off < len && data->target != NULL)
+		off += cmd_prarg(buf + off, len - off, " -t ", data->target);
+	if (off < len && data->template != NULL)
+		off += cmd_prarg(buf + off, len - off, " ", data->template);
+	return (off);
+}
+
 int
 cmd_command_prompt_callback(void *data, const char *s)
 {
-	struct cmd_command_prompt_data	*cdata = data;
+	struct cmd_command_prompt_cdata	*cdata = data;
 	struct client			*c = cdata->c;
 	struct cmd_list			*cmdlist;
-	struct cmd_ctx	 		 ctx;
-	char				*cause, *ptr, *buf, ch;
-	size_t				 len, slen;
+	struct cmd_ctx			 ctx;
+	char				*cause, *newtempl, *prompt, *ptr;
 
-	if (s == NULL || *s == '\0')
+	if (s == NULL)
 		return (0);
-	slen = strlen(s);
 
-	len = 0;
-	buf = NULL;
-	if (cdata->template != NULL) {
-		ptr = cdata->template;
-		while (*ptr != '\0') {
-			switch (ch = *ptr++) {
-			case '%':
-				if (*ptr != '%')
-					break;
-				ptr++;
+	newtempl = cmd_command_prompt_replace(cdata->template, s, cdata->idx);
+	xfree(cdata->template);
+	cdata->template = newtempl;
 
-				buf = xrealloc(buf, 1, len + slen + 1);
-				memcpy(buf + len, s, slen);
-				len += slen;
-				break;
-			default:
-				buf = xrealloc(buf, 1, len + 2);
-				buf[len++] = ch;
-				break;
-			}
+	if ((ptr = strsep(&cdata->next_prompt, ",")) != NULL) {
+		xasprintf(&prompt, "%s ", ptr);
+		status_prompt_update(c, prompt);
+		xfree(prompt);
+		cdata->idx++;
+		return (1);
+	}
+
+	if (cmd_string_parse(newtempl, &cmdlist, &cause) != 0) {
+		if (cause != NULL) {
+			*cause = toupper((u_char) *cause);
+			status_message_set(c, "%s", cause);
+			xfree(cause);
 		}
-
-		if (buf == NULL)
-			return (0);
-		buf[len] = '\0';
-		s = buf;
-	}
-
-	if (cmd_string_parse(s, &cmdlist, &cause) != 0) {
-		if (cause == NULL)
-			return (0);
-		*cause = toupper((u_char) *cause);
-		status_message_set(c, "%s", cause);
-		xfree(cause);
-		cmdlist = NULL;
-	}
-	if (buf != NULL)
-		xfree(buf);
-	if (cmdlist == NULL)
 		return (0);
+	}
 
 	ctx.msgdata = NULL;
 	ctx.cursession = c->session;
@@ -176,11 +256,53 @@ cmd_command_prompt_callback(void *data, const char *s)
 }
 
 void
-cmd_command_prompt_free(void *data)
+cmd_command_prompt_cfree(void *data)
 {
-	struct cmd_command_prompt_data	*cdata = data;
+	struct cmd_command_prompt_cdata	*cdata = data;
 
+	if (cdata->prompts != NULL)
+		xfree(cdata->prompts);
 	if (cdata->template != NULL)
 		xfree(cdata->template);
 	xfree(cdata);
 }
+
+char *
+cmd_command_prompt_replace(char *template, const char *s, int idx)
+{
+	char	 ch;
+	char	*buf, *ptr;
+	int	 replaced;
+	size_t	 len;
+
+	if (strstr(template, "%") == NULL)
+		return (xstrdup(template));
+
+	buf = xmalloc(1);
+	*buf = '\0';
+	len = 0;
+	replaced = 0;
+
+	ptr = template;
+	while (*ptr != '\0') {
+		switch (ch = *ptr++) {
+		case '%':
+			if (*ptr < '1' || *ptr > '9' || *ptr - '0' != idx) {
+				if (*ptr != '%' || replaced)
+					break;
+				replaced = 1;
+			}
+			ptr++;
+
+			len += strlen(s);
+			buf = xrealloc(buf, 1, len + 1);
+			strlcat(buf, s, len + 1);
+			continue;
+		}
+		buf = xrealloc(buf, 1, len + 2);
+		buf[len++] = ch;
+		buf[len] = '\0';
+	}
+
+	return (buf);
+}
diff --git a/status.c b/status.c
index d700f2c7..b4f23702 100644
--- a/status.c
+++ b/status.c
@@ -668,6 +668,20 @@ status_prompt_clear(struct client *c)
 	screen_reinit(&c->status);
 }
 
+void
+status_prompt_update(struct client *c, const char *msg)
+{
+	xfree(c->prompt_string);
+	c->prompt_string = xstrdup(msg);
+
+	*c->prompt_buffer = '\0';
+	c->prompt_index = 0;
+
+	c->prompt_hindex = 0;
+
+	c->flags |= CLIENT_STATUS;
+}
+
 /* Draw client prompt on status line of present else on last line. */
 int
 status_prompt_redraw(struct client *c)
diff --git a/tmux.1 b/tmux.1
index b811c81e..f5f05f06 100644
--- a/tmux.1
+++ b/tmux.1
@@ -1662,6 +1662,7 @@ session option.
 Commands related to the status line are as follows:
 .Bl -tag -width Ds
 .It Xo Ic command-prompt
+.Op Fl p Ar prompts
 .Op Fl t Ar target-client
 .Op Ar template
 .Xc
@@ -1671,8 +1672,30 @@ This may be used from inside
 to execute commands interactively.
 If
 .Ar template
-is specified, it is used as the command; any %% in the template will be
-replaced by what is entered at the prompt.
+is specified, it is used as the command.
+If
+.Fl p
+is given,
+.Ar prompts
+is a comma-separated list of prompts which are displayed in order; otherwise
+a single prompt is displayed, constructed from
+.Ar template
+if it is present, or
+.Ql \&:
+if not.
+Before the command is executed, the first occurrence of the string
+.Ql %%
+and all occurences of
+.Ql %1
+are replaced by the response to the first prompt, the second
+.Ql %%
+and all
+.Ql %2
+are replaced with the response to the second prompt, and so on for further
+prompts. Up to nine prompt responses may be replaced
+.Ns ( Ql %1
+to
+.Ns Ql %9 ) .
 .It Xo Ic confirm-before
 .Op Fl t Ar target-client
 .Ar command
@@ -1926,6 +1949,7 @@ Creating new key bindings:
 .Bd -literal -offset indent
 bind-key b set-option status
 bind-key / command-prompt "split-window 'exec man %%'"
+bind-key S command-prompt "new-window -n %1 'ssh %1'"
 .Ed
 .Sh SEE ALSO
 .Xr pty 4
diff --git a/tmux.h b/tmux.h
index f70d1f5c..4b388360 100644
--- a/tmux.h
+++ b/tmux.h
@@ -1440,6 +1440,7 @@ void	 status_prompt_set(struct client *, const char *,
 void	 status_prompt_clear(struct client *);
 int	 status_prompt_redraw(struct client *);
 void	 status_prompt_key(struct client *, int);
+void	 status_prompt_update(struct client *, const char *);
 
 /* resize.c */
 void	 recalculate_sizes(void);