diff --git a/doc/sudo_plugin.cat b/doc/sudo_plugin.cat
index aab7b6bb7..ad1ff85d7 100644
--- a/doc/sudo_plugin.cat
+++ b/doc/sudo_plugin.cat
@@ -1336,6 +1336,7 @@ DDEESSCCRRIIPPTTIIOONN
      #define SUDO_CONV_INFO_MSG         0x0004 /* informational message */
      #define SUDO_CONV_PROMPT_MASK      0x0005 /* mask user input */
      #define SUDO_CONV_PROMPT_ECHO_OK   0x1000 /* flag: allow echo if no tty */
+     #define SUDO_CONV_PREFER_TTY       0x2000 /* flag: use tty if possible */
          int msg_type;
          int timeout;
          const char *msg;
@@ -1382,6 +1383,49 @@ DDEESSCCRRIIPPTTIIOONN
      them when the process is resumed.  Note that the functions are not
      actually invoked from within a signal handler.
 
+     The _m_s_g___t_y_p_e must be set to one of the following values:
+
+     SUDO_CONV_PROMPT_ECHO_OFF
+           Prompt the user for input with echo disabled; this is generally
+           used for passwords.  The reply will be stored in the _r_e_p_l_i_e_s array.
+
+     SUDO_CONV_PROMPT_ECHO_ON
+           Prompt the user for input with echo enabled.  The reply will be
+           stored in the _r_e_p_l_i_e_s array.
+
+     SUDO_CONV_ERROR_MSG
+           Display an error message.  The message is written to the standard
+           error unless the SUDO_CONV_PREFER_TTY flag is set, in which case it
+           is written to the user's terminal if possible.
+
+     SUDO_CONV_INFO_MSG
+           Display a message.  The message is written to the standard output
+           unless the SUDO_CONV_PREFER_TTY flag is set, in which case it is
+           written to the user's terminal if possible.
+
+     SUDO_CONV_PROMPT_MASK
+           Prompt the user for input but echo an asterisk character for each
+           character read.  The reply will be stored in the _r_e_p_l_i_e_s This can
+           be used to provide visual feedback to the user while reading
+           sensitive information that should not be displayed.
+
+     In addition to the above values, the following flag bits may also be set:
+
+     SUDO_CONV_PROMPT_ECHO_OK
+           Allow input to be read when echo cannot be disabled when the
+           message type is SUDO_CONV_PROMPT_ECHO_OFF or SUDO_CONV_PROMPT_MASK.
+           By default, ssuuddoo will refuse to read input if the echo cannot be
+           disabled for those message types.
+
+     SUDO_CONV_PREFER_TTY
+           When displaying a message via SUDO_CONV_ERROR_MSG or
+           SUDO_CONV_INFO_MSG, try to write the message to the user's
+           terminal.  If the terminal is unavailable, the standard error or
+           standard output will be used, depending upon whether The user's
+           terminal is always used when possible for input, this flag is only
+           used for output.  SUDO_CONV_ERROR_MSG or SUDO_CONV_INFO_MSG was
+           used.
+
      The plugin is responsible for freeing the reply buffer located in each
      struct sudo_conv_reply, if it is not NULL.  SUDO_CONV_REPL_MAX represents
      the maximum length of the reply buffer (not including the trailing NUL
@@ -1604,4 +1648,4 @@ DDIISSCCLLAAIIMMEERR
      file distributed with ssuuddoo or https://www.sudo.ws/license.html for
      complete details.
 
-Sudo 1.8.23                     March 21, 2018                     Sudo 1.8.23
+Sudo 1.8.24                      June 1, 2018                      Sudo 1.8.24
diff --git a/doc/sudo_plugin.man.in b/doc/sudo_plugin.man.in
index 06f10409c..73419b558 100644
--- a/doc/sudo_plugin.man.in
+++ b/doc/sudo_plugin.man.in
@@ -15,7 +15,7 @@
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.TH "SUDO_PLUGIN" "5" "March 21, 2018" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
+.TH "SUDO_PLUGIN" "5" "June 1, 2018" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
 .nh
 .if n .ad l
 .SH "NAME"
@@ -2354,6 +2354,7 @@ struct sudo_conv_message {
 #define SUDO_CONV_INFO_MSG         0x0004 /* informational message */
 #define SUDO_CONV_PROMPT_MASK      0x0005 /* mask user input */
 #define SUDO_CONV_PROMPT_ECHO_OK   0x1000 /* flag: allow echo if no tty */
+#define SUDO_CONV_PREFER_TTY       0x2000 /* flag: use tty if possible */
     int msg_type;
     int timeout;
     const char *msg;
@@ -2436,6 +2437,71 @@ that should not be held indefinitely while suspended and then reacquire them
 when the process is resumed.
 Note that the functions are not actually invoked from within a signal handler.
 .PP
+The
+\fImsg_type\fR
+must be set to one of the following values:
+.TP 6n
+SUDO_CONV_PROMPT_ECHO_OFF
+Prompt the user for input with echo disabled;
+this is generally used for passwords.
+The reply will be stored in the
+\fIreplies\fR
+array.
+.TP 6n
+SUDO_CONV_PROMPT_ECHO_ON
+Prompt the user for input with echo enabled.
+The reply will be stored in the
+\fIreplies\fR
+array.
+.TP 6n
+SUDO_CONV_ERROR_MSG
+Display an error message.
+The message is written to the standard error unless the
+\fRSUDO_CONV_PREFER_TTY\fR
+flag is set, in which case it is written to the user's terminal if possible.
+.TP 6n
+SUDO_CONV_INFO_MSG
+Display a message.
+The message is written to the standard output unless the
+\fRSUDO_CONV_PREFER_TTY\fR
+flag is set, in which case it is written to the user's terminal if possible.
+.TP 6n
+SUDO_CONV_PROMPT_MASK
+Prompt the user for input but echo an asterisk character for each
+character read.
+The reply will be stored in the
+\fIreplies\fR
+This can be used to provide visual feedback to the user while reading
+sensitive information that should not be displayed.
+.PP
+In addition to the above values, the following flag bits may also be set:
+.TP 6n
+SUDO_CONV_PROMPT_ECHO_OK
+Allow input to be read when echo cannot be disabled
+when the message type is
+\fRSUDO_CONV_PROMPT_ECHO_OFF\fR
+or
+\fRSUDO_CONV_PROMPT_MASK\fR.
+By default,
+\fBsudo\fR
+will refuse to read input if the echo cannot be disabled for those
+message types.
+.TP 6n
+SUDO_CONV_PREFER_TTY
+When displaying a message via
+\fRSUDO_CONV_ERROR_MSG\fR
+or
+\fRSUDO_CONV_INFO_MSG\fR,
+try to write the message to the user's terminal.
+If the terminal is unavailable, the standard error or standard output
+will be used, depending upon whether
+The user's terminal is always used when possible for input,
+this flag is only used for output.
+\fRSUDO_CONV_ERROR_MSG\fR
+or
+\fRSUDO_CONV_INFO_MSG\fR
+was used.
+.PP
 The plugin is responsible for freeing the reply buffer located in each
 \fRstruct sudo_conv_reply\fR,
 if it is not
diff --git a/doc/sudo_plugin.mdoc.in b/doc/sudo_plugin.mdoc.in
index d38bbd092..5150e23c1 100644
--- a/doc/sudo_plugin.mdoc.in
+++ b/doc/sudo_plugin.mdoc.in
@@ -14,7 +14,7 @@
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd March 21, 2018
+.Dd June 1, 2018
 .Dt SUDO_PLUGIN @mansectform@
 .Os Sudo @PACKAGE_VERSION@
 .Sh NAME
@@ -2048,6 +2048,7 @@ struct sudo_conv_message {
 #define SUDO_CONV_INFO_MSG         0x0004 /* informational message */
 #define SUDO_CONV_PROMPT_MASK      0x0005 /* mask user input */
 #define SUDO_CONV_PROMPT_ECHO_OK   0x1000 /* flag: allow echo if no tty */
+#define SUDO_CONV_PREFER_TTY       0x2000 /* flag: use tty if possible */
     int msg_type;
     int timeout;
     const char *msg;
@@ -2126,6 +2127,68 @@ that should not be held indefinitely while suspended and then reacquire them
 when the process is resumed.
 Note that the functions are not actually invoked from within a signal handler.
 .Pp
+The
+.Em msg_type
+must be set to one of the following values:
+.Bl -tag -width 4n
+.It SUDO_CONV_PROMPT_ECHO_OFF
+Prompt the user for input with echo disabled;
+this is generally used for passwords.
+The reply will be stored in the
+.Em replies
+array.
+.It SUDO_CONV_PROMPT_ECHO_ON
+Prompt the user for input with echo enabled.
+The reply will be stored in the
+.Em replies
+array.
+.It SUDO_CONV_ERROR_MSG
+Display an error message.
+The message is written to the standard error unless the
+.Dv SUDO_CONV_PREFER_TTY
+flag is set, in which case it is written to the user's terminal if possible.
+.It SUDO_CONV_INFO_MSG
+Display a message.
+The message is written to the standard output unless the
+.Dv SUDO_CONV_PREFER_TTY
+flag is set, in which case it is written to the user's terminal if possible.
+.It SUDO_CONV_PROMPT_MASK
+Prompt the user for input but echo an asterisk character for each
+character read.
+The reply will be stored in the
+.Em replies
+This can be used to provide visual feedback to the user while reading
+sensitive information that should not be displayed.
+.El
+.Pp
+In addition to the above values, the following flag bits may also be set:
+.Bl -tag -width 4n
+.It SUDO_CONV_PROMPT_ECHO_OK
+Allow input to be read when echo cannot be disabled
+when the message type is
+.Dv SUDO_CONV_PROMPT_ECHO_OFF
+or
+.Dv SUDO_CONV_PROMPT_MASK .
+By default,
+.Nm sudo
+will refuse to read input if the echo cannot be disabled for those
+message types.
+.It SUDO_CONV_PREFER_TTY
+When displaying a message via
+.Dv SUDO_CONV_ERROR_MSG
+or
+.Dv SUDO_CONV_INFO_MSG ,
+try to write the message to the user's terminal.
+If the terminal is unavailable, the standard error or standard output
+will be used, depending upon whether
+The user's terminal is always used when possible for input,
+this flag is only used for output.
+.Dv SUDO_CONV_ERROR_MSG
+or
+.Dv SUDO_CONV_INFO_MSG
+was used.
+.El
+.Pp
 The plugin is responsible for freeing the reply buffer located in each
 .Li struct sudo_conv_reply ,
 if it is not
diff --git a/include/sudo_plugin.h b/include/sudo_plugin.h
index efe82df66..bd22076ea 100644
--- a/include/sudo_plugin.h
+++ b/include/sudo_plugin.h
@@ -41,6 +41,7 @@ struct sudo_conv_message {
 #define SUDO_CONV_INFO_MSG	    0x0004  /* informational message */
 #define SUDO_CONV_PROMPT_MASK	    0x0005  /* mask user input */
 #define SUDO_CONV_PROMPT_ECHO_OK    0x1000  /* flag: allow echo if no tty */
+#define SUDO_CONV_PREFER_TTY	    0x2000  /* flag: use tty if possible */
     int msg_type;
     int timeout;
     const char *msg;
diff --git a/src/conversation.c b/src/conversation.c
index 7c7b3c3ad..a7b5091bf 100644
--- a/src/conversation.c
+++ b/src/conversation.c
@@ -29,8 +29,9 @@
 #ifdef HAVE_STRINGS_H
 # include <strings.h>
 #endif /* HAVE_STRINGS_H */
-#include <unistd.h>
 #include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
 
 #include "sudo.h"
 #include "sudo_plugin.h"
@@ -46,7 +47,7 @@ sudo_conversation(int num_msgs, const struct sudo_conv_message msgs[],
     struct sudo_conv_reply replies[], struct sudo_conv_callback *callback)
 {
     char *pass;
-    int n;
+    int fd, n;
     const int conv_debug_instance = sudo_debug_get_active_instance();
 
     sudo_debug_set_active_instance(sudo_debug_instance);
@@ -54,6 +55,7 @@ sudo_conversation(int num_msgs, const struct sudo_conv_message msgs[],
     for (n = 0; n < num_msgs; n++) {
 	const struct sudo_conv_message *msg = &msgs[n];
 	int flags = tgetpass_flags;
+	FILE *fp = stdout;
 
 	switch (msg->msg_type & 0xff) {
 	    case SUDO_CONV_PROMPT_ECHO_ON:
@@ -77,13 +79,22 @@ sudo_conversation(int num_msgs, const struct sudo_conv_message msgs[],
 		}
 		memset_s(pass, SUDO_CONV_REPL_MAX, 0, strlen(pass));
 		break;
-	    case SUDO_CONV_INFO_MSG:
-		if (msg->msg != NULL && fputs(msg->msg, stdout) == EOF)
-		    goto err;
-		break;
 	    case SUDO_CONV_ERROR_MSG:
-		if (msg->msg != NULL && fputs(msg->msg, stderr) == EOF)
-		    goto err;
+		fp = stderr;
+		/* FALLTHROUGH */
+	    case SUDO_CONV_INFO_MSG:
+		if (msg->msg != NULL) {
+		    if (ISSET(msg->msg_type, SUDO_CONV_PREFER_TTY)) {
+			/* Try writing to /dev/tty first. */
+			if ((fd = open(_PATH_TTY, O_WRONLY)) != -1) {
+			    if (write(fd, msg->msg, strlen(msg->msg)) != -1)
+				break;
+			    close(fd);
+			}
+		    }
+		    if (fputs(msg->msg, fp) == EOF)
+			goto err;
+		}
 		break;
 	    default:
 		goto err;
