diff --git a/man/launcher.1.md b/man/launcher.1.md
index d2afb561a2d7107a4bc04d12a39868f2857de1df..4f0c512767d57398724ebbaf125c7b4d920a8235 100644
--- a/man/launcher.1.md
+++ b/man/launcher.1.md
@@ -12,6 +12,7 @@ pressure-vessel-launcher - server to launch processes in a container
 **pressure-vessel-launcher**
 [**--replace**]
 [**--verbose**]
+[**--info-fd**] *N*
 {**--bus-name** *NAME*|**--socket** *SOCKET*|**--socket-directory** *PATH*}
 
 # DESCRIPTION
@@ -52,6 +53,11 @@ D-Bus session bus, and executes arbitrary commands as subprocesses.
     readable, meaning either data is available or end-of-file has been
     reached.
 
+**--info-fd** *FD*
+:   Print details of the server on *FD* (see **OUTPUT** below).
+    This fd will be closed (reach end-of-file) when the server is ready.
+    The default is standard output, equivalent to **--info-fd=1**.
+
 **--replace**
 :   When used with **--bus-name**, allow other
     **pressure-vessel-launcher** processes to take over the bus name,
@@ -64,7 +70,9 @@ D-Bus session bus, and executes arbitrary commands as subprocesses.
 # OUTPUT
 
 **pressure-vessel-launcher** prints zero or more lines of
-structured text on standard output, and then closes standard output:
+structured text on the file descriptor specified by **--info-fd**,
+and then closes both the **--info-fd** and standard output. The default
+**--info-fd** is standard output.
 
 **socket=**PATH
 :   The launcher is listening on *PATH*, and can be contacted by
@@ -86,11 +94,12 @@ structured text on standard output, and then closes standard output:
     (such as **dbus-send --session**) to the session bus and sending
     method calls to _NAME_.
 
-Clients must wait until after standard output has been closed, or wait
-for the bus name to appear, before connecting by bus name.
+Clients must wait until after either the **--info-fd** or standard output
+has been closed, or wait for the bus name to appear, before connecting
+by bus name.
 
-Clients must wait until after standard output has been closed before
-connecting by socket name.
+Clients must wait until after either the **--info-fd** or standard output
+has been closed before connecting by socket name.
 
 Unstructured diagnostic messages are printed on standard error,
 which remains open throughout.
@@ -211,13 +220,15 @@ instead of fifos.
     mkfifo "${tmpdir}/ready-fifo"
     pressure-vessel-wrap \
         --filesystem="${tmpdir}" \
+        --pass-fd=3
         ... \
         -- \
         pressure-vessel-launcher \
             --exit-on-readable=0 \
+            --info-fd=3 \
             --socket="${tmpdir}/launcher" \
         < "${tmpdir}/exit-fifo" \
-        > "${tmpdir}/ready-fifo" \
+        3> "${tmpdir}/ready-fifo" \
         &
     launcher_pid="$!"
     sleep infinity > "${tmpdir}/exit-fifo" &
diff --git a/src/launcher.c b/src/launcher.c
index e26df69e5db7426c06e5768b1da511881e644cac..6e76b72d892fb95b95f7eb8b6296a762f987da6b 100644
--- a/src/launcher.c
+++ b/src/launcher.c
@@ -57,12 +57,27 @@ typedef GDBusServer AutoDBusServer;
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(AutoDBusServer, g_object_unref)
 
 static FILE *original_stdout = NULL;
+static FILE *info_fh = NULL;
 static GDBusConnection *session_bus = NULL;
 static GHashTable *client_pid_data_hash = NULL;
 static guint name_owner_id = 0;
 static GMainLoop *main_loop;
 static PvLauncher1 *launcher;
 
+/*
+ * Close the --info-fd, and also close standard output (if different).
+ */
+static void
+close_info_fh (void)
+{
+  if (info_fh == original_stdout)
+    original_stdout = NULL;
+  else
+    g_clear_pointer (&original_stdout, fclose);
+
+  g_clear_pointer (&info_fh, fclose);
+}
+
 static void
 skeleton_died_cb (gpointer data)
 {
@@ -558,10 +573,10 @@ on_name_acquired (GDBusConnection *connection,
   if (*ret == EX_UNAVAILABLE)
     {
       *ret = 0;
-      g_assert (original_stdout != NULL);
-      fprintf (original_stdout, "bus_name=%s\n", name);
-      fflush (original_stdout);
-      g_clear_pointer (&original_stdout, fclose);
+      g_assert (info_fh != NULL);
+      fprintf (info_fh, "bus_name=%s\n", name);
+      fflush (info_fh);
+      close_info_fh ();
     }
 }
 
@@ -963,6 +978,7 @@ set_up_exit_on_readable (int fd,
 
 static gchar *opt_bus_name = NULL;
 static gint opt_exit_on_readable_fd = -1;
+static gint opt_info_fd = -1;
 static gboolean opt_replace = FALSE;
 static gchar *opt_socket = NULL;
 static gchar *opt_socket_directory = NULL;
@@ -980,6 +996,11 @@ static GOptionEntry options[] =
     "Exit when data is available for reading or when end-of-file is "
     "reached on this fd, usually 0 for stdin.",
     "FD" },
+  { "info-fd", '\0',
+    G_OPTION_FLAG_NONE, G_OPTION_ARG_INT, &opt_info_fd,
+    "Indicate readiness and print details of how to connect on this "
+    "file descriptor instead of stdout.",
+    "FD" },
   { "replace", '\0',
     G_OPTION_FLAG_NONE, G_OPTION_ARG_NONE, &opt_replace,
     "Replace a previous instance with the same bus name. "
@@ -1076,6 +1097,24 @@ main (int argc,
       goto out;
     }
 
+  if (opt_info_fd > 0)   /* < 0 means unset, and 0 is stdout itself */
+    {
+      info_fh = fdopen (opt_info_fd, "w");
+
+      if (info_fh == NULL)
+        {
+          glnx_null_throw_errno_prefix (error,
+                                        "Unable to create a stdio wrapper for fd %d",
+                                        opt_info_fd);
+          ret = EX_OSERR;
+          goto out;
+        }
+    }
+  else
+    {
+      info_fh = original_stdout;
+    }
+
   if (opt_exit_on_readable_fd >= 0)
     {
       if (!set_up_exit_on_readable (opt_exit_on_readable_fd,
@@ -1261,16 +1300,16 @@ main (int argc,
     }
 
   if (opt_socket != NULL)
-    fprintf (original_stdout, "socket=%s\n", opt_socket);
+    fprintf (info_fh, "socket=%s\n", opt_socket);
 
   if (server != NULL)
-    fprintf (original_stdout, "dbus_address=%s\n",
+    fprintf (info_fh, "dbus_address=%s\n",
              g_dbus_server_get_client_address (server));
 
   if (opt_bus_name == NULL)
     {
-      fflush (original_stdout);
-      g_clear_pointer (&original_stdout, fclose);
+      fflush (info_fh);
+      close_info_fh ();
     }
 
   g_debug ("Entering main loop");
@@ -1307,7 +1346,7 @@ out:
     ret = EX_UNAVAILABLE;
 
   g_clear_error (&local_error);
-  g_clear_pointer (&original_stdout, fclose);
+  close_info_fh ();
 
   g_debug ("Exiting with status %d", ret);
   return ret;