diff --git a/doc/sudoers.cat b/doc/sudoers.cat
index 39752453c..b0caee934 100644
--- a/doc/sudoers.cat
+++ b/doc/sudoers.cat
@@ -1615,6 +1615,16 @@ SSUUDDOOEERRSS OOPPTTIIOONNSS
                        will be truncated and overwritten unless _i_o_l_o_g___f_i_l_e
                        ends in six or more Xs.
 
+     iolog_flush       If set, ssuuddoo will flush I/O log data to disk after each
+                       write instead of buffering it.  This makes it possible
+                       to view the logs in real-time as the program is
+                       executing but may significantly reduce the
+                       effectiveness of I/O log compression.  This flag is _o_f_f
+                       by default.
+
+                       This setting is only supported by version 1.8.20 or
+                       higher.
+
      iolog_group       The group name to look up when setting the group ID on
                        new I/O log files and directories.  By default, I/O log
                        files and directories inherit the group ID of the
@@ -2241,12 +2251,14 @@ II//OO LLOOGG FFIILLEESS
      _s_t_d_e_r_r    standard error to a pipe or redirected to a file
 
      All files other than _l_o_g are compressed in gzip format unless the
-     _c_o_m_p_r_e_s_s___i_o option has been disabled.  Due to buffering, it is not
-     possible to display the I/O logs in real-time as the program is
-     executing.  The I/O log data will not be complete until the program run
-     by ssuuddoo has exited or has been terminated by a signal.  The output
-     portion of an I/O log file can be viewed with the sudoreplay(1m) utility,
-     which can also be used to list or search the available logs.
+     _c_o_m_p_r_e_s_s___i_o flag has been disabled.  Due to buffering, it is not normally
+     possible to display the I/O logs in real-time as the program is executing
+     The I/O log data will not be complete until the program run by ssuuddoo has
+     exited or has been terminated by a signal.  The _i_o_l_o_g___f_l_u_s_h flag can be
+     used to disable buffering, in which case I/O log data is written to disk
+     as soon as it is available.  The output portion of an I/O log file can be
+     viewed with the sudoreplay(1m) utility, which can also be used to list or
+     search the available logs.
 
      Note that user input may contain sensitive information such as passwords
      (even if they are not echoed to the screen), which will be stored in the
@@ -2748,4 +2760,4 @@ DDIISSCCLLAAIIMMEERR
      file distributed with ssuuddoo or https://www.sudo.ws/license.html for
      complete details.
 
-Sudo 1.8.20                     March 17, 2017                     Sudo 1.8.20
+Sudo 1.8.20                     March 20, 2017                     Sudo 1.8.20
diff --git a/doc/sudoers.man.in b/doc/sudoers.man.in
index a9ff75415..49dbd77ad 100644
--- a/doc/sudoers.man.in
+++ b/doc/sudoers.man.in
@@ -21,7 +21,7 @@
 .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
 .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
 .\"
-.TH "SUDOERS" "5" "March 17, 2017" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
+.TH "SUDOERS" "5" "March 20, 2017" "Sudo @PACKAGE_VERSION@" "File Formats Manual"
 .nh
 .if n .ad l
 .SH "NAME"
@@ -3315,6 +3315,19 @@ ends in six or
 more
 \fRX\fRs.
 .TP 18n
+iolog_flush
+If set,
+\fBsudo\fR
+will flush I/O log data to disk after each write instead of buffering it.
+This makes it possible to view the logs in real-time as the program
+is executing but may significantly reduce the effectiveness of I/O
+log compression.
+This flag is
+\fIoff\fR
+by default.
+.sp
+This setting is only supported by version 1.8.20 or higher.
+.TP 18n
 iolog_group
 The group name to look up when setting the group ID on new I/O log
 files and directories.
@@ -4467,12 +4480,16 @@ All files other than
 \fIlog\fR
 are compressed in gzip format unless the
 \fIcompress_io\fR
-option has been disabled.
-Due to buffering, it is not possible to display the I/O logs in
-real-time as the program is executing.
+flag has been disabled.
+Due to buffering, it is not normally possible to display the I/O logs in
+real-time as the program is executing
 The I/O log data will not be complete until the program run by
 \fBsudo\fR
 has exited or has been terminated by a signal.
+The
+\fIiolog_flush\fR
+flag can be used to disable buffering, in which case I/O log data
+is written to disk as soon as it is available.
 The output portion of an I/O log file can be viewed with the
 sudoreplay(@mansectsu@)
 utility, which can also be used to list or search the available logs.
diff --git a/doc/sudoers.mdoc.in b/doc/sudoers.mdoc.in
index 97ac155c7..e872b7c6a 100644
--- a/doc/sudoers.mdoc.in
+++ b/doc/sudoers.mdoc.in
@@ -19,7 +19,7 @@
 .\" Agency (DARPA) and Air Force Research Laboratory, Air Force
 .\" Materiel Command, USAF, under agreement number F39502-99-1-0512.
 .\"
-.Dd March 17, 2017
+.Dd March 20, 2017
 .Dt SUDOERS @mansectform@
 .Os Sudo @PACKAGE_VERSION@
 .Sh NAME
@@ -3109,6 +3109,18 @@ overwritten unless
 ends in six or
 more
 .Li X Ns s .
+.It iolog_flush
+If set,
+.Nm sudo
+will flush I/O log data to disk after each write instead of buffering it.
+This makes it possible to view the logs in real-time as the program
+is executing but may significantly reduce the effectiveness of I/O
+log compression.
+This flag is
+.Em off
+by default.
+.Pp
+This setting is only supported by version 1.8.20 or higher.
 .It iolog_group
 The group name to look up when setting the group ID on new I/O log
 files and directories.
@@ -4148,12 +4160,16 @@ All files other than
 .Pa log
 are compressed in gzip format unless the
 .Em compress_io
-option has been disabled.
-Due to buffering, it is not possible to display the I/O logs in
-real-time as the program is executing.
+flag has been disabled.
+Due to buffering, it is not normally possible to display the I/O logs in
+real-time as the program is executing
 The I/O log data will not be complete until the program run by
 .Nm sudo
 has exited or has been terminated by a signal.
+The
+.Em iolog_flush
+flag can be used to disable buffering, in which case I/O log data
+is written to disk as soon as it is available.
 The output portion of an I/O log file can be viewed with the
 .Xr sudoreplay @mansectsu@
 utility, which can also be used to list or search the available logs.
diff --git a/plugins/sudoers/def_data.c b/plugins/sudoers/def_data.c
index 501d7804e..331a6b428 100644
--- a/plugins/sudoers/def_data.c
+++ b/plugins/sudoers/def_data.c
@@ -457,6 +457,10 @@ struct sudo_defs_types sudo_defs_table[] = {
 	"user_command_timeouts", T_FLAG,
 	N_("Allow the user to specify a timeout on the command line"),
 	NULL,
+    }, {
+	"iolog_flush", T_FLAG,
+	N_("Flush I/O log data to disk immediately instead of buffering it"),
+	NULL,
     }, {
 	NULL, 0, NULL
     }
diff --git a/plugins/sudoers/def_data.h b/plugins/sudoers/def_data.h
index 2f749b53b..c52335236 100644
--- a/plugins/sudoers/def_data.h
+++ b/plugins/sudoers/def_data.h
@@ -212,6 +212,8 @@
 #define def_command_timeout     (sudo_defs_table[I_COMMAND_TIMEOUT].sd_un.ival)
 #define I_USER_COMMAND_TIMEOUTS 106
 #define def_user_command_timeouts (sudo_defs_table[I_USER_COMMAND_TIMEOUTS].sd_un.flag)
+#define I_IOLOG_FLUSH           107
+#define def_iolog_flush         (sudo_defs_table[I_IOLOG_FLUSH].sd_un.flag)
 
 enum def_tuple {
 	never,
diff --git a/plugins/sudoers/def_data.in b/plugins/sudoers/def_data.in
index b5fb4d92e..a005a6c01 100644
--- a/plugins/sudoers/def_data.in
+++ b/plugins/sudoers/def_data.in
@@ -335,3 +335,6 @@ command_timeout
 user_command_timeouts
 	T_FLAG
 	"Allow the user to specify a timeout on the command line"
+iolog_flush
+	T_FLAG
+	"Flush I/O log data to disk immediately instead of buffering it"
diff --git a/plugins/sudoers/iolog.c b/plugins/sudoers/iolog.c
index f1ab3c406..058659d51 100644
--- a/plugins/sudoers/iolog.c
+++ b/plugins/sudoers/iolog.c
@@ -710,6 +710,7 @@ iolog_deserialize_info(struct iolog_details *details, char * const user_info[],
 
 /*
  * Write the "/log" file that contains the user and command info.
+ * This file is not compressed.
  */
 static bool
 write_info_log(char *pathbuf, size_t len, struct iolog_details *details,
@@ -748,6 +749,57 @@ write_info_log(char *pathbuf, size_t len, struct iolog_details *details,
     debug_return_bool(ret);
 }
 
+#ifdef HAVE_ZLIB_H
+static const char *
+gzstrerror(gzFile file)
+{
+    int errnum;
+
+    return gzerror(file, &errnum);
+}
+#endif /* HAVE_ZLIB_H */
+
+/*
+ * Write to an I/O log, compressing if iolog_compress is enabled.
+ * If def_iolog_flush is true, flush the buffer immediately.
+ */
+static const char *
+iolog_write(const void *buf, unsigned int len, int idx)
+{
+    const char *errstr = NULL;
+    debug_decl(iolog_write, SUDOERS_DEBUG_PLUGIN)
+
+#ifdef HAVE_ZLIB_H
+    if (iolog_compress) {
+	if (gzwrite(io_log_files[idx].fd.g, buf, len) != (int)len) {
+	    errstr = gzstrerror(io_log_files[idx].fd.g);
+	    goto done;
+	}
+	if (def_iolog_flush) {
+	    if (gzflush(io_log_files[idx].fd.g, Z_SYNC_FLUSH) != Z_OK) {
+		errstr = gzstrerror(io_log_files[idx].fd.g);
+		goto done;
+	    }
+	}
+    } else
+#endif
+    {
+	if (fwrite(buf, 1, len, io_log_files[idx].fd.f) != len) {
+	    errstr = strerror(errno);
+	    goto done;
+	}
+	if (def_iolog_flush) {
+	    if (fflush(io_log_files[idx].fd.f) != 0) {
+		errstr = strerror(errno);
+		goto done;
+	    }
+	}
+    }
+
+done:
+    debug_return_const_str(errstr);
+}
+
 static int
 sudoers_io_open(unsigned int version, sudo_conv_t conversation,
     sudo_printf_t plugin_printf, char * const settings[],
@@ -915,13 +967,15 @@ sudoers_io_version(int verbose)
 
 /*
  * Generic I/O logging function.  Called by the I/O logging entry points.
+ * Returns 1 on success and -1 on error.
  */
 static int
 sudoers_io_log(const char *buf, unsigned int len, int idx)
 {
     struct timeval now, delay;
+    char tbuf[1024];
     const char *errstr = NULL;
-    int ret = true;
+    int ret = -1;
     debug_decl(sudoers_io_version, SUDOERS_DEBUG_PLUGIN)
 
     if (io_log_files[idx].fd.v == NULL) {
@@ -932,41 +986,28 @@ sudoers_io_log(const char *buf, unsigned int len, int idx)
 
     gettimeofday(&now, NULL);
 
-#ifdef HAVE_ZLIB_H
-    if (iolog_compress) {
-	if (gzwrite(io_log_files[idx].fd.g, (const voidp)buf, len) != (int)len) {
-	    int errnum;
+    /* Write I/O log file entry. */
+    errstr = iolog_write(buf, len, idx);
+    if (errstr != NULL)
+	goto done;
 
-	    errstr = gzerror(io_log_files[idx].fd.g, &errnum);
-	    ret = -1;
-	}
-    } else
-#endif
-    {
-	if (fwrite(buf, 1, len, io_log_files[idx].fd.f) != len) {
-	    errstr = strerror(errno);
-	    ret = -1;
-	}
-    }
+    /* Write timing file entry. */
     sudo_timevalsub(&now, &last_time, &delay);
-#ifdef HAVE_ZLIB_H
-    if (iolog_compress) {
-	if (gzprintf(io_log_files[IOFD_TIMING].fd.g, "%d %f %u\n", idx,
-	    delay.tv_sec + ((double)delay.tv_usec / 1000000), len) == 0) {
-	    int errnum;
-
-	    errstr = gzerror(io_log_files[IOFD_TIMING].fd.g, &errnum);
-	    ret = -1;
-	}
-    } else
-#endif
-    {
-	if (fprintf(io_log_files[IOFD_TIMING].fd.f, "%d %f %u\n", idx,
-	    delay.tv_sec + ((double)delay.tv_usec / 1000000), len) < 0) {
-	    errstr = strerror(errno);
-	    ret = -1;
-	}
+    len = (unsigned int)snprintf(tbuf, sizeof(tbuf), "%d %f %u\n", idx,
+	delay.tv_sec + ((double)delay.tv_usec / 1000000), len);
+    if (len >= sizeof(tbuf)) {
+	/* Not actually possible due to the size of tbuf[]. */
+	errstr = strerror(EOVERFLOW);
+	goto done;
     }
+    errstr = iolog_write(tbuf, len, IOFD_TIMING);
+    if (errstr != NULL)
+	goto done;
+
+    /* Success. */
+    ret = 1;
+
+done:
     last_time.tv_sec = now.tv_sec;
     last_time.tv_usec = now.tv_usec;
 
@@ -980,7 +1021,7 @@ sudoers_io_log(const char *buf, unsigned int len, int idx)
 
 	/* Ignore errors if they occur if the policy says so. */
 	if (iolog_details.ignore_iolog_errors)
-	    ret = true;
+	    ret = 1;
     }
 
     debug_return_int(ret);
