diff --git a/src/box/iproto.cc b/src/box/iproto.cc
index 809e534db675951701e5bba40a1d8d22755c68ac..a5db59fd984024fc533b8383ab22a95932781b15 100644
--- a/src/box/iproto.cc
+++ b/src/box/iproto.cc
@@ -653,6 +653,7 @@ iproto_process(struct iproto_request *ireq)
 	if (unlikely(! evio_is_active(&con->output)))
 		return;
 
+	ireq->session->sync = ireq->header.sync;
 	struct obuf_svp svp = obuf_create_svp(out);
 	try {
 		switch (ireq->header.type) {
diff --git a/src/box/lua/session.cc b/src/box/lua/session.cc
index 8571df71296bb92baa96f68902268a54c234808d..991f2205b5be8fd2ecb77693671194e6485cb7f7 100644
--- a/src/box/lua/session.cc
+++ b/src/box/lua/session.cc
@@ -60,6 +60,18 @@ lbox_session_id(struct lua_State *L)
 	return 1;
 }
 
+/**
+ * Return the id of currently executed request.
+ * Many requests share the same session so this is only
+ * valid at session start. 0 for non-iproto sessions.
+ */
+static int
+lbox_session_sync(struct lua_State *L)
+{
+	lua_pushnumber(L, current_session()->sync);
+	return 1;
+}
+
 /**
  * Session user id.
  * Note: effective user id (current_user()->uid)
@@ -249,6 +261,7 @@ box_lua_session_init(struct lua_State *L)
 {
 	static const struct luaL_reg sessionlib[] = {
 		{"id", lbox_session_id},
+		{"sync", lbox_session_sync},
 		{"uid", lbox_session_uid},
 		{"user", lbox_session_user},
 		{"su", lbox_session_su},
diff --git a/src/box/session.cc b/src/box/session.cc
index 840ef3a0f01f1549fac86aa7e4db4b4274c1d645..e694f7c8543bc0ca4b049de2c744f91b54b2896a 100644
--- a/src/box/session.cc
+++ b/src/box/session.cc
@@ -76,6 +76,7 @@ session_create(int fd, uint64_t cookie)
 	session->id = sid_max();
 	session->fd =  fd;
 	session->cookie = cookie;
+	session->sync = 0;
 	/* For on_connect triggers. */
 	credentials_init(&session->credentials, guest_user);
 	if (fd >= 0)
diff --git a/src/box/session.h b/src/box/session.h
index e1720f51b692c5462a86bc1a34f6a6ed6d49c248..09a9ea34a52ba27c76a1a2d44497830a192b59c2 100644
--- a/src/box/session.h
+++ b/src/box/session.h
@@ -48,10 +48,24 @@ enum {	SESSION_SEED_SIZE = 32, SESSION_DELIM_SIZE = 16 };
 struct session {
 	/** Session id. */
 	uint32_t id;
-	/** File descriptor - socket of the connected peer. */
+	/** File descriptor - socket of the connected peer.
+	 * Only if the session has a peer.
+	 */
 	int fd;
-	/** Peer cookie - description of the peer. */
+	/**
+	 * Peer cookie - description of the peer.
+	 * Only if the session has a peer.
+	 */
 	uint64_t cookie;
+	/**
+	 * For iproto requests, we set this field
+	 * to the value of packet sync. Since the
+	 * session may be reused between many requests,
+	 * the value is true only at the beginning
+	 * of the request, and gets distorted after
+	 * the first yield.
+	 */
+	uint64_t sync;
 	/** Authentication salt. */
 	char salt[SESSION_SEED_SIZE];
 	/** Cached user id and global grants */
diff --git a/test/box/session.result b/test/box/session.result
index 1d254e10f7cbfd2c77c4eb609f504ad67007633e..dead886005596ab1d45d415b5849938099a761b8 100644
--- a/test/box/session.result
+++ b/test/box/session.result
@@ -193,6 +193,10 @@ a:call('dostring', 'return space:get{session.id()}[1] == session.id()')[1][1]
 ---
 - true
 ...
+a:eval('return session.sync() ~= 0')
+---
+- true
+...
 a:close()
 ---
 ...
@@ -218,6 +222,10 @@ session.user()
 ---
 - admin
 ...
+session.sync()
+---
+- 0
+...
 fiber = nil
 ---
 ...
diff --git a/test/box/session.test.lua b/test/box/session.test.lua
index 3474dbb34c855ff435049962204afd4ffc242ff5..56e5a0c35016c45117d2066664115a646b18ef90 100644
--- a/test/box/session.test.lua
+++ b/test/box/session.test.lua
@@ -75,6 +75,7 @@ session.on_disconnect(audit_disconnect)
 box.schema.user.grant('guest', 'read,write,execute', 'universe')
 a = net.box:new(LISTEN.host, LISTEN.service)
 a:call('dostring', 'return space:get{session.id()}[1] == session.id()')[1][1]
+a:eval('return session.sync() ~= 0')
 a:close()
 
 -- cleanup
@@ -86,6 +87,7 @@ space:drop()
 
 session.uid()
 session.user()
+session.sync()
 fiber = nil
 session = nil
 box.schema.user.revoke('guest', 'read,write,execute', 'universe')