diff --git a/include/recovery.h b/include/recovery.h
index d19acc32477ab7cfa61d801367896379a7176cfe..8228b4d104096dda93a9f649a9c8e5e0a0fc40c2 100644
--- a/include/recovery.h
+++ b/include/recovery.h
@@ -67,12 +67,15 @@ wait_lsn_clear(struct wait_lsn *wait_lsn)
 struct wal_writer;
 struct wal_watcher;
 
+enum { REMOTE_SOURCE_MAXLEN = 32 };
+
 /** Master connection */
 struct remote {
 	struct sockaddr_in addr;
 	struct fiber *reader;
 	uint64_t cookie;
 	ev_tstamp recovery_lag, recovery_last_update_tstamp;
+	char source[REMOTE_SOURCE_MAXLEN];
 };
 
 enum wal_mode { WAL_NONE = 0, WAL_WRITE, WAL_FSYNC, WAL_FSYNC_DELAY, WAL_MODE_MAX };
diff --git a/include/tarantool.h b/include/tarantool.h
index a32850acf2e7ec8c319df578f1fe377079e217f7..e3cba7b0eac42e4769427e4638282baea2fa2823 100644
--- a/include/tarantool.h
+++ b/include/tarantool.h
@@ -45,6 +45,7 @@ extern char *cfg_filename_fullpath;
 extern bool booting;
 extern char *binary_filename;
 extern char *custom_proc_title;
+extern char status[];
 int reload_cfg(struct tbuf *out);
 void show_cfg(struct tbuf *out);
 int snapshot(void);
@@ -52,10 +53,8 @@ const char *tarantool_version(void);
 double tarantool_uptime(void);
 void tarantool_free(void);
 
-char **init_set_proc_title(int argc, char **argv);
-void free_proc_title(int argc, char **argv);
-void set_proc_title(const char *format, ...);
-void title(const char *fmt, ...);
+void __attribute__((format (printf, 2, 3)))
+title(const char *role, const char *fmt, ...);
 
 #define DEFAULT_CFG_FILENAME "tarantool.cfg"
 #define DEFAULT_CFG SYSCONF_DIR "/" DEFAULT_CFG_FILENAME
diff --git a/src/box/box.cc b/src/box/box.cc
index 008635cc24ae62c5fcc6b1dcc3bf87dfa4cd59e7..fd0ad87c8e4e2c186f8ddc08d54dbc99f8c9204f 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -60,8 +60,6 @@ static void process_rw(struct port *port,
 box_process_func box_process = process_ro;
 box_process_func box_process_ro = process_ro;
 
-static char status[64] = "unknown";
-
 static int stat_base;
 
 struct box_snap_row {
@@ -192,19 +190,12 @@ box_enter_master_or_replica_mode(struct tarantool_cfg *conf)
 
 		recovery_wait_lsn(recovery_state, recovery_state->lsn);
 		recovery_follow_remote(recovery_state, conf->replication_source);
-
-		snprintf(status, sizeof(status), "replica/%s%s",
-			 conf->replication_source, custom_proc_title);
-		title("replica/%s%s", conf->replication_source,
-		      custom_proc_title);
 	} else {
 		box_process = process_rw;
 
 		memcached_start_expire();
 
-		snprintf(status, sizeof(status), "primary%s",
-			 custom_proc_title);
-		title("primary%s", custom_proc_title);
+		title("primary", NULL);
 
 		say_info("I am primary");
 	}
@@ -326,7 +317,7 @@ box_free(void)
 void
 box_init(bool init_storage)
 {
-	title("loading");
+	title("loading", NULL);
 
 	/* initialization spaces */
 	space_init();
@@ -355,13 +346,11 @@ box_init(bool init_storage)
 
 	say_info("building secondary indexes");
 	build_secondary_indexes();
-	title("orphan");
+	title("orphan", NULL);
 	if (cfg.local_hot_standby) {
 		say_info("starting local hot standby");
 		recovery_follow_local(recovery_state, cfg.wal_dir_rescan_delay);
-		snprintf(status, sizeof(status), "hot_standby%s",
-			 custom_proc_title);
-		title("hot_standby%s", custom_proc_title);
+		title("hot_standby", NULL);
 	}
 }
 
diff --git a/src/replica.cc b/src/replica.cc
index b4acbb7744c372eab532d7efd5e29a35d3005e4b..d4ce43956f972f210dfaeb83a492bd645ba19bbd 100644
--- a/src/replica.cc
+++ b/src/replica.cc
@@ -36,6 +36,7 @@
 #include "fiber.h"
 #include "pickle.h"
 #include "coio_buf.h"
+#include "tarantool.h"
 
 static void
 remote_apply_row(struct recovery_state *r, const char *row, uint32_t rowlne);
@@ -103,11 +104,15 @@ pull_from_remote(va_list ap)
 		try {
 			fiber_setcancellable(true);
 			if (! evio_is_active(&coio)) {
+				title("replica", "%s/%s", r->remote->source,
+				      "connecting");
 				if (iobuf == NULL)
 					iobuf = iobuf_new(fiber_name(fiber));
 				remote_connect(&coio, &r->remote->addr,
 					       r->confirmed_lsn + 1, &err);
 				warning_said = false;
+				title("replica", "%s/%s", r->remote->source,
+				      "connected");
 			}
 			err = "can't read row";
 			uint32_t rowlen;
@@ -123,10 +128,12 @@ pull_from_remote(va_list ap)
 			iobuf_gc(iobuf);
 			fiber_gc();
 		} catch (const FiberCancelException& e) {
+			title("replica", "%s/%s", r->remote->source, "failed");
 			iobuf_delete(iobuf);
 			evio_close(&coio);
 			throw;
 		} catch (const Exception& e) {
+			title("replica", "%s/%s", r->remote->source, "failed");
 			e.log();
 			if (! warning_said) {
 				if (err != NULL)
@@ -190,6 +197,7 @@ recovery_follow_remote(struct recovery_state *r, const char *addr)
 	remote.addr.sin_port = htons(port);
 	memcpy(&remote.cookie, &remote.addr, MIN(sizeof(remote.cookie), sizeof(remote.addr)));
 	remote.reader = f;
+	snprintf(remote.source, sizeof(remote.source), "%s", addr);
 	r->remote = &remote;
 	fiber_call(f, r);
 }
diff --git a/src/replication.cc b/src/replication.cc
index 53d896adf434bc52b5d67e69ea69fb1088c1d88d..071eba7c109e898e2f296f88cd6e089a4bb79a2d 100644
--- a/src/replication.cc
+++ b/src/replication.cc
@@ -299,12 +299,10 @@ replication_send_socket(ev_io *watcher, int events __attribute__((unused)))
 static void
 spawner_init(int sock)
 {
-	char name[FIBER_NAME_MAXLEN];
 	struct sigaction sa;
 
-	snprintf(name, sizeof(name), "spawner%s", custom_proc_title);
-	fiber_set_name(fiber, name);
-	set_proc_title(name);
+	title("spawner", NULL);
+	fiber_set_name(fiber, status);
 
 	/* init replicator process context */
 	spawner.sock = sock;
@@ -609,7 +607,6 @@ replication_relay_send_row(void *param, const char *row, uint32_t rowlen)
 static void
 replication_relay_loop(int client_sock)
 {
-	char name[FIBER_NAME_MAXLEN];
 	struct sigaction sa;
 	int64_t lsn;
 	ssize_t r;
@@ -621,9 +618,8 @@ replication_relay_loop(int client_sock)
 	struct sockaddr_in peer;
 	socklen_t addrlen = sizeof(peer);
 	getpeername(client_sock, ((struct sockaddr*)&peer), &addrlen);
-	snprintf(name, sizeof(name), "relay/%s", sio_strfaddr(&peer));
-	fiber_set_name(fiber, name);
-	set_proc_title("%s%s", name, custom_proc_title);
+	title("relay", "%s", sio_strfaddr(&peer));
+	fiber_set_name(fiber, status);
 
 	/* init signals */
 	memset(&sa, 0, sizeof(sa));
diff --git a/src/tarantool.cc b/src/tarantool.cc
index f04e4eafcf94f47da8e3ea2e25a23bf2f58d81f0..24f0520ed687b394c216b4d52221c4314d9ff4a1 100644
--- a/src/tarantool.cc
+++ b/src/tarantool.cc
@@ -77,6 +77,7 @@ const char *cfg_filename = NULL;
 char *cfg_filename_fullpath = NULL;
 char *binary_filename;
 char *custom_proc_title;
+char status[64] = "unknown";
 char **main_argv;
 int main_argc;
 static void *main_opt = NULL;
@@ -90,6 +91,13 @@ uint32_t snapshot_version = 0;
 
 extern const void *opt_def;
 
+/* defined in third_party/proctitle.c */
+extern "C" {
+char **init_set_proc_title(int argc, char **argv);
+void free_proc_title(int argc, char **argv);
+void set_proc_title(const char *format, ...);
+} /* extern "C" */
+
 static int
 core_check_config(struct tarantool_cfg *conf)
 {
@@ -102,14 +110,26 @@ core_check_config(struct tarantool_cfg *conf)
 }
 
 void
-title(const char *fmt, ...)
+title(const char *role, const char *fmt, ...)
 {
+	(void) role;
+
 	va_list ap;
 	char buf[128], *bufptr = buf, *bufend = buf + sizeof(buf);
-
-	va_start(ap, fmt);
-	bufptr += vsnprintf(bufptr, bufend - bufptr, fmt, ap);
-	va_end(ap);
+	char *statusptr = status, *statusend = status + sizeof(status);
+	statusptr += snprintf(statusptr, statusend - statusptr, "%s", role);
+	bufptr += snprintf(bufptr, bufend - bufptr, "%s%s", role,
+			    custom_proc_title);
+
+	if (fmt != NULL) {
+		const char *s = statusptr;
+		statusptr += snprintf(statusptr, statusend - statusptr, "/");
+		va_start(ap, fmt);
+		statusptr += vsnprintf(statusptr, statusend - statusptr,
+				       fmt, ap);
+		va_end(ap);
+		bufptr += snprintf(bufptr, bufend - bufptr, "%s", s);
+	}
 
 	int ports[] = { cfg.primary_port, cfg.secondary_port,
 			cfg.memcached_port, cfg.admin_port,
@@ -341,8 +361,8 @@ snapshot(void)
 
 	salloc_protect();
 
-	fiber_set_name(fiber, "dumper");
-	set_proc_title("dumper (%" PRIu32 ")", getppid());
+	title("dumper", "%" PRIu32, getppid());
+	fiber_set_name(fiber, status);
 
 	/*
 	 * Safety: make sure we don't double-write
diff --git a/test/replication/status.result b/test/replication/status.result
new file mode 100644
index 0000000000000000000000000000000000000000..dbde422651c9a2cfcc7cf081472dd40b13ed257c
--- /dev/null
+++ b/test/replication/status.result
@@ -0,0 +1,2 @@
+True
+True
diff --git a/test/replication/status.test b/test/replication/status.test
new file mode 100644
index 0000000000000000000000000000000000000000..759078c4f06190281ffdda0b5c0f64217b48db82
--- /dev/null
+++ b/test/replication/status.test
@@ -0,0 +1,28 @@
+# encoding: tarantool
+import os
+import time
+import re
+from lib.tarantool_server import TarantoolServer
+
+# replica server
+replica = TarantoolServer()
+replica.deploy("replication/cfg/replica.cfg",
+               replica.find_exe(self.args.builddir),
+               os.path.join(self.args.vardir, "replica"))
+
+replica.get_param("lsn")
+
+status = replica.admin.execute_no_reconnect("lua box.info.status", True)
+print(re.search(r'replica/.*/(connecting|connected)\n', status) != None)
+
+server.stop()
+status = replica.admin.execute_no_reconnect("lua box.info.status", True)
+print(re.search(r'replica/.*/(connecting|failed)\n', status) != None)
+
+# Cleanup.
+replica.stop()
+replica.cleanup(True)
+
+server.deploy(self.suite_ini["config"])
+
+# vim: syntax=python