diff --git a/include/types/global.h b/include/types/global.h
index aeb82eae9..ee8e95e0e 100644
--- a/include/types/global.h
+++ b/include/types/global.h
@@ -44,7 +44,7 @@
 #define	MODE_VERBOSE	0x10
 #define	MODE_STARTING	0x20
 #define	MODE_FOREGROUND	0x40
-#define	MODE_SYSTEMD	0x80
+#define	MODE_MWORKER	0x80    /* Master Worker */
 
 /* list of last checks to perform, depending on config options */
 #define LSTCHK_CAP_BIND	0x00000001	/* check that we can bind to any port */
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 4c0e2d4f0..bdf55a8da 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -624,6 +624,11 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm)
 			goto out;
 		global.mode |= MODE_DAEMON;
 	}
+	else if (!strcmp(args[0], "master-worker")) {
+		if (alertif_too_many_args(0, file, linenum, args, &err_code))
+			goto out;
+		global.mode |= MODE_MWORKER;
+	}
 	else if (!strcmp(args[0], "debug")) {
 		if (alertif_too_many_args(0, file, linenum, args, &err_code))
 			goto out;
diff --git a/src/haproxy.c b/src/haproxy.c
index 6ecae257d..0e8511bf1 100644
--- a/src/haproxy.c
+++ b/src/haproxy.c
@@ -348,6 +348,7 @@ static void usage(char *name)
 		"        -dM[<byte>] poisons memory with <byte> (defaults to 0x50)\n"
 		"        -V enters verbose mode (disables quiet mode)\n"
 		"        -D goes daemon ; -C changes to <dir> before loading files.\n"
+		"        -W master-worker mode.\n"
 		"        -q quiet mode : don't display messages\n"
 		"        -c check mode : only check config files and exit\n"
 		"        -n sets the maximum total # of connections (%d)\n"
@@ -921,11 +922,10 @@ static void init(int argc, char **argv)
 				arg_mode |= MODE_DEBUG;
 			else if (*flag == 'c')
 				arg_mode |= MODE_CHECK;
-			else if (*flag == 'D') {
+			else if (*flag == 'D')
 				arg_mode |= MODE_DAEMON;
-				if (flag[1] == 's')  /* -Ds */
-					arg_mode |= MODE_SYSTEMD;
-			}
+			else if (*flag == 'W')
+				arg_mode |= MODE_MWORKER;
 			else if (*flag == 'q')
 				arg_mode |= MODE_QUIET;
 			else if (*flag == 'x') {
@@ -1001,7 +1001,7 @@ static void init(int argc, char **argv)
 	}
 
 	global.mode = MODE_STARTING | /* during startup, we want most of the alerts */
-		(arg_mode & (MODE_DAEMON | MODE_SYSTEMD | MODE_FOREGROUND | MODE_VERBOSE
+		(arg_mode & (MODE_DAEMON | MODE_MWORKER | MODE_FOREGROUND | MODE_VERBOSE
 			     | MODE_QUIET | MODE_CHECK | MODE_DEBUG));
 
 	if (change_dir && chdir(change_dir) < 0) {
@@ -1330,24 +1330,24 @@ static void init(int argc, char **argv)
 
 	if (arg_mode & (MODE_DEBUG | MODE_FOREGROUND)) {
 		/* command line debug mode inhibits configuration mode */
-		global.mode &= ~(MODE_DAEMON | MODE_SYSTEMD | MODE_QUIET);
+		global.mode &= ~(MODE_DAEMON | MODE_QUIET);
 		global.mode |= (arg_mode & (MODE_DEBUG | MODE_FOREGROUND));
 	}
 
-	if (arg_mode & (MODE_DAEMON | MODE_SYSTEMD)) {
+	if (arg_mode & MODE_DAEMON) {
 		/* command line daemon mode inhibits foreground and debug modes mode */
 		global.mode &= ~(MODE_DEBUG | MODE_FOREGROUND);
-		global.mode |= (arg_mode & (MODE_DAEMON | MODE_SYSTEMD));
+		global.mode |= arg_mode & MODE_DAEMON;
 	}
 
 	global.mode |= (arg_mode & (MODE_QUIET | MODE_VERBOSE));
 
-	if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_SYSTEMD | MODE_QUIET))) {
-		Warning("<debug> mode incompatible with <quiet>, <daemon> and <systemd>. Keeping <debug> only.\n");
-		global.mode &= ~(MODE_DAEMON | MODE_SYSTEMD | MODE_QUIET);
+	if ((global.mode & MODE_DEBUG) && (global.mode & (MODE_DAEMON | MODE_QUIET))) {
+		Warning("<debug> mode incompatible with <quiet> and <daemon>. Keeping <debug> only.\n");
+		global.mode &= ~(MODE_DAEMON | MODE_QUIET);
 	}
 
-	if ((global.nbproc > 1) && !(global.mode & (MODE_DAEMON | MODE_SYSTEMD))) {
+	if ((global.nbproc > 1) && !(global.mode & (MODE_DAEMON | MODE_MWORKER))) {
 		if (!(global.mode & (MODE_FOREGROUND | MODE_DEBUG)))
 			Warning("<nbproc> is only meaningful in daemon mode. Setting limit to 1 process.\n");
 		global.nbproc = 1;
@@ -2020,7 +2020,7 @@ int main(int argc, char **argv)
 	}
 
 	/* open log & pid files before the chroot */
-	if (global.mode & (MODE_DAEMON | MODE_SYSTEMD) && global.pidfile != NULL) {
+	if (global.mode & MODE_DAEMON && global.pidfile != NULL) {
 		unlink(global.pidfile);
 		pidfd = open(global.pidfile, O_CREAT | O_WRONLY | O_TRUNC, 0644);
 		if (pidfd < 0) {
@@ -2047,14 +2047,17 @@ int main(int argc, char **argv)
 			" might not work well.\n"
 			"", argv[0]);
 
-	/* chroot if needed */
-	if (global.chroot != NULL) {
-		if (chroot(global.chroot) == -1 || chdir("/") == -1) {
-			Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
-			if (nb_oldpids)
-				tell_old_pids(SIGTTIN);
-			protocol_unbind_all();
-			exit(1);
+	if ((global.mode & (MODE_MWORKER|MODE_DAEMON)) == 0) {
+
+		/* chroot if needed */
+		if (global.chroot != NULL) {
+			if (chroot(global.chroot) == -1 || chdir("/") == -1) {
+				Alert("[%s.main()] Cannot chroot(%s).\n", argv[0], global.chroot);
+				if (nb_oldpids)
+					tell_old_pids(SIGTTIN);
+				protocol_unbind_all();
+				exit(1);
+			}
 		}
 	}
 
@@ -2065,25 +2068,26 @@ int main(int argc, char **argv)
 	 * be able to restart the old pids.
 	 */
 
-	/* setgid / setuid */
-	if (global.gid) {
-		if (getgroups(0, NULL) > 0 && setgroups(0, NULL) == -1)
-			Warning("[%s.main()] Failed to drop supplementary groups. Using 'gid'/'group'"
-				" without 'uid'/'user' is generally useless.\n", argv[0]);
+	if ((global.mode & (MODE_MWORKER|MODE_DAEMON)) == 0) {
+		/* setgid / setuid */
+		if (global.gid) {
+			if (getgroups(0, NULL) > 0 && setgroups(0, NULL) == -1)
+				Warning("[%s.main()] Failed to drop supplementary groups. Using 'gid'/'group'"
+					" without 'uid'/'user' is generally useless.\n", argv[0]);
 
-		if (setgid(global.gid) == -1) {
-			Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
+			if (setgid(global.gid) == -1) {
+				Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
+				protocol_unbind_all();
+				exit(1);
+			}
+		}
+
+		if (global.uid && setuid(global.uid) == -1) {
+			Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
 			protocol_unbind_all();
 			exit(1);
 		}
 	}
-
-	if (global.uid && setuid(global.uid) == -1) {
-		Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
-		protocol_unbind_all();
-		exit(1);
-	}
-
 	/* check ulimits */
 	limit.rlim_cur = limit.rlim_max = 0;
 	getrlimit(RLIMIT_NOFILE, &limit);
@@ -2092,7 +2096,7 @@ int main(int argc, char **argv)
 			argv[0], (int)limit.rlim_cur, global.maxconn, global.maxsock, global.maxsock);
 	}
 
-	if (global.mode & (MODE_DAEMON | MODE_SYSTEMD)) {
+	if (global.mode & (MODE_DAEMON | MODE_MWORKER)) {
 		struct proxy *px;
 		struct peers *curpeers;
 		int ret = 0;
@@ -2100,6 +2104,22 @@ int main(int argc, char **argv)
 		int proc;
 		char *wrapper_fd;
 
+		/*
+		 * if daemon + mworker: must fork here to let a master
+		 * process live in background before forking children
+		 */
+		if ((global.mode & MODE_MWORKER) && (global.mode & MODE_DAEMON)) {
+			ret = fork();
+			if (ret < 0) {
+				Alert("[%s.main()] Cannot fork.\n", argv[0]);
+				protocol_unbind_all();
+				exit(1); /* there has been an error */
+			}
+			/* parent leave to daemonize */
+			if (ret > 0)
+				exit(0);
+		}
+
 		/* the father launches the required number of processes */
 		for (proc = 0; proc < global.nbproc; proc++) {
 			ret = fork();
@@ -2146,19 +2166,11 @@ int main(int argc, char **argv)
 
 		/* We won't ever use this anymore */
 		free(oldpids);        oldpids = NULL;
-		free(global.chroot);  global.chroot = NULL;
 		free(global.pidfile); global.pidfile = NULL;
 
 		if (proc == global.nbproc) {
-			if (global.mode & MODE_SYSTEMD) {
-				int i;
-
+			if (global.mode & MODE_MWORKER) {
 				protocol_unbind_all();
-				for (i = 1; i < argc; i++) {
-					memset(argv[i], '\0', strlen(argv[i]));
-				}
-				/* it's OK because "-Ds -f x" is the shortest form going here */
-				memcpy(argv[0] + strlen(argv[0]), "-master", 8);
 				for (proc = 0; proc < global.nbproc; proc++)
 					while (waitpid(-1, NULL, 0) == -1 && errno == EINTR);
 			}
@@ -2168,6 +2180,40 @@ int main(int argc, char **argv)
 			exit(0); /* parent must leave */
 		}
 
+		/* Must chroot and setgid/setuid in the children */
+		/* chroot if needed */
+		if (global.chroot != NULL) {
+			if (chroot(global.chroot) == -1 || chdir("/") == -1) {
+				Alert("[%s.main()] Cannot chroot1(%s).\n", argv[0], global.chroot);
+				if (nb_oldpids)
+					tell_old_pids(SIGTTIN);
+				protocol_unbind_all();
+				exit(1);
+			}
+		}
+
+		free(global.chroot);
+		global.chroot = NULL;
+
+		/* setgid / setuid */
+		if (global.gid) {
+			if (getgroups(0, NULL) > 0 && setgroups(0, NULL) == -1)
+				Warning("[%s.main()] Failed to drop supplementary groups. Using 'gid'/'group'"
+					" without 'uid'/'user' is generally useless.\n", argv[0]);
+
+			if (setgid(global.gid) == -1) {
+				Alert("[%s.main()] Cannot set gid %d.\n", argv[0], global.gid);
+				protocol_unbind_all();
+				exit(1);
+			}
+		}
+
+		if (global.uid && setuid(global.uid) == -1) {
+			Alert("[%s.main()] Cannot set uid %d.\n", argv[0], global.uid);
+			protocol_unbind_all();
+			exit(1);
+		}
+
 		/* pass through every cli socket, and check if it's bound to
 		 * the current process and if it exposes listeners sockets.
 		 * Caution: the GTUNE_SOCKET_TRANSFER is now set after the fork.
diff --git a/src/listener.c b/src/listener.c
index a99e4c0d3..69da2b77f 100644
--- a/src/listener.c
+++ b/src/listener.c
@@ -53,7 +53,7 @@ struct xfer_sock_list *xfer_sock_list = NULL;
 void enable_listener(struct listener *listener)
 {
 	if (listener->state == LI_LISTEN) {
-		if ((global.mode & (MODE_DAEMON | MODE_SYSTEMD)) &&
+		if ((global.mode & (MODE_DAEMON | MODE_MWORKER)) &&
 		    listener->bind_conf->bind_proc &&
 		    !(listener->bind_conf->bind_proc & (1UL << (relative_pid - 1)))) {
 			/* we don't want to enable this listener and don't
@@ -135,7 +135,7 @@ int pause_listener(struct listener *l)
  */
 int resume_listener(struct listener *l)
 {
-	if ((global.mode & (MODE_DAEMON | MODE_SYSTEMD)) &&
+	if ((global.mode & (MODE_DAEMON | MODE_MWORKER)) &&
 	    l->bind_conf->bind_proc &&
 	    !(l->bind_conf->bind_proc & (1UL << (relative_pid - 1))))
 		return 1;