diff --git a/src/box/iproto.cc b/src/box/iproto.cc
index f31738cb03e7e160bd98473cb7adcf489ed423c7..9dad43b0b8ebf538cd4542c116c226d9782e8ffa 100644
--- a/src/box/iproto.cc
+++ b/src/box/iproto.cc
@@ -129,6 +129,23 @@ unsigned iproto_readahead = 16320;
 /* The maximal number of iproto messages in fly. */
 static int iproto_msg_max = IPROTO_MSG_MAX_MIN;
 
+/**
+ * Address the iproto listens for, stored in TX
+ * thread. Is kept in TX to be shown in box.info.
+ */
+static struct sockaddr_storage iproto_bound_address_storage;
+/** 0 means that no address is listened. */
+static socklen_t iproto_bound_address_len;
+
+const char *
+iproto_bound_address(void)
+{
+	if (iproto_bound_address_len == 0)
+		return NULL;
+	return sio_strfaddr((struct sockaddr *) &iproto_bound_address_storage,
+			    iproto_bound_address_len);
+}
+
 /**
  * How big is a buffer which needs to be shrunk before
  * it is put back into buffer cache.
@@ -2203,8 +2220,14 @@ struct iproto_cfg_msg: public cbus_call_msg
 	/** Operation to execute in iproto thread. */
 	enum iproto_cfg_op op;
 	union {
-		/** New URI to bind to. */
-		const char *uri;
+		struct {
+			/** New URI to bind to. */
+			const char *uri;
+			/** Result address. */
+			struct sockaddr_storage addr;
+			/** Address length. */
+			socklen_t addrlen;
+		};
 
 		/** New iproto max message count. */
 		int iproto_msg_max;
@@ -2240,6 +2263,8 @@ iproto_do_cfg_f(struct cbus_call_msg *m)
 			    (evio_service_bind(&binary, cfg_msg->uri) != 0 ||
 			     evio_service_listen(&binary) != 0))
 				diag_raise();
+			cfg_msg->addrlen = binary.addr_len;
+			cfg_msg->addr = binary.addrstorage;
 			break;
 		default:
 			unreachable();
@@ -2265,6 +2290,8 @@ iproto_listen(const char *uri)
 	iproto_cfg_msg_create(&cfg_msg, IPROTO_CFG_LISTEN);
 	cfg_msg.uri = uri;
 	iproto_do_cfg(&cfg_msg);
+	iproto_bound_address_storage = cfg_msg.addr;
+	iproto_bound_address_len = cfg_msg.addrlen;
 }
 
 size_t
diff --git a/src/box/iproto.h b/src/box/iproto.h
index edb24a7edf55b0656b37316eeda87b5daec47637..1442e68d3db35d663d9ea48da841fd56893668ee 100644
--- a/src/box/iproto.h
+++ b/src/box/iproto.h
@@ -80,6 +80,13 @@ iproto_request_count(void);
 void
 iproto_reset_stat(void);
 
+/**
+ * String representation of the address served by
+ * iproto. To be shown in box.info.
+ */
+const char *
+iproto_bound_address(void);
+
 #if defined(__cplusplus)
 } /* extern "C" */
 
diff --git a/src/box/lua/info.c b/src/box/lua/info.c
index c004fad27264cb9b2bd134d867e32d095f9974da..a789f782288d58b66f63e1f11ee78b536f003655 100644
--- a/src/box/lua/info.c
+++ b/src/box/lua/info.c
@@ -518,6 +518,14 @@ lbox_info_sql(struct lua_State *L)
 	return 1;
 }
 
+static int
+lbox_info_listen(struct lua_State *L)
+{
+	/* NULL is ok, no need to check. */
+	lua_pushstring(L, iproto_bound_address());
+	return 1;
+}
+
 static const struct luaL_Reg lbox_info_dynamic_meta[] = {
 	{"id", lbox_info_id},
 	{"uuid", lbox_info_uuid},
@@ -534,6 +542,7 @@ static const struct luaL_Reg lbox_info_dynamic_meta[] = {
 	{"gc", lbox_info_gc},
 	{"vinyl", lbox_info_vinyl},
 	{"sql", lbox_info_sql},
+	{"listen", lbox_info_listen},
 	{NULL, NULL}
 };
 
diff --git a/src/lib/core/evio.c b/src/lib/core/evio.c
index 2152c15e6c2ef3acf615becb4a1eb9502d2c04a8..fc8f00e0ef5e69e208467e3b373dc637094687ff 100644
--- a/src/lib/core/evio.c
+++ b/src/lib/core/evio.c
@@ -269,6 +269,13 @@ evio_service_bind_addr(struct evio_service *service)
 		}
 	}
 
+	/*
+	 * After binding a result address may be different. For
+	 * example, if a port was 0.
+	 */
+	if (sio_getsockname(fd, &service->addr, &service->addr_len) != 0)
+		goto error;
+
 	say_info("%s: bound to %s", evio_service_name(service),
 		 sio_strfaddr(&service->addr, service->addr_len));
 
@@ -400,6 +407,7 @@ evio_service_stop(struct evio_service *service)
 
 	if (ev_is_active(&service->ev)) {
 		ev_io_stop(service->loop, &service->ev);
+		service->addr_len = 0;
 	}
 
 	if (service->ev.fd >= 0) {
diff --git a/test/box-tap/cfg.test.lua b/test/box-tap/cfg.test.lua
index d529447bbd526d9610db8cebb494ed1f55f53939..569b5f463d3cbafa88f68ef57eb0f13379b4774a 100755
--- a/test/box-tap/cfg.test.lua
+++ b/test/box-tap/cfg.test.lua
@@ -6,7 +6,7 @@ local socket = require('socket')
 local fio = require('fio')
 local uuid = require('uuid')
 local msgpack = require('msgpack')
-test:plan(104)
+test:plan(108)
 
 --------------------------------------------------------------------------------
 -- Invalid values
@@ -592,6 +592,18 @@ box.cfg{read_only=true}
 ]]
 test:is(run_script(code), PANIC, "panic on bootstrapping a read-only instance as master")
 
+--
+-- gh-4620: box.info.listen.
+--
+box.cfg{listen = box.NULL}
+test:is(nil, box.info.listen, 'no cfg.listen - no info.listen')
+
+box.cfg{listen = '127.0.0.1:0'}
+test:ok(box.info.listen:match('127.0.0.1'), 'real IP in info.listen')
+test:ok(not box.info.listen:match(':0'), 'real port in info.listen')
+
+box.cfg{listen = box.NULL}
+test:is(nil, box.info.listen, 'cfg.listen reset drops info.listen')
 
 test:check()
 os.exit(0)
diff --git a/test/box/info.result b/test/box/info.result
index 2e84cbbe3e7274bb6d61d4ef6a5e9297afb08970..e6d0ba6aa914f3e6f188a97f8e16fc0761120462 100644
--- a/test/box/info.result
+++ b/test/box/info.result
@@ -77,6 +77,7 @@ t
 - - cluster
   - gc
   - id
+  - listen
   - lsn
   - memory
   - package