diff --git a/src/box/alter.cc b/src/box/alter.cc
index 7df8e0ba6ef3af3f28f274e358e0abbeedc6b18f..061647c4fe4e3116bcb43c8b7392b3cc182a5651 100644
--- a/src/box/alter.cc
+++ b/src/box/alter.cc
@@ -63,7 +63,7 @@
 static void
 access_check_ddl(uint32_t owner_uid, enum schema_object_type type)
 {
-	struct credentials *cr = current_user();
+	struct credentials *cr = effective_user();
 	/*
 	 * Only the owner of the object can be the grantor
 	 * of the privilege on the object. This means that
diff --git a/src/box/box.cc b/src/box/box.cc
index bf46bdc30bf0fc0aef5149e093c831a938661856..eb443c7441e5971f5babcb31ab4920af47ea9f07 100644
--- a/src/box/box.cc
+++ b/src/box/box.cc
@@ -1008,7 +1008,7 @@ sequence_data_update(uint32_t seq_id, int64_t value)
 			 mp_encode_uint(tuple_buf_end, value));
 	assert(tuple_buf_end < tuple_buf + tuple_buf_size);
 
-	struct credentials *orig_credentials = current_user();
+	struct credentials *orig_credentials = effective_user();
 	fiber_set_user(fiber(), &admin_credentials);
 
 	int rc = box_replace(BOX_SEQUENCE_DATA_ID,
@@ -1033,7 +1033,7 @@ sequence_data_delete(uint32_t seq_id)
 	key_buf_end = mp_encode_uint(key_buf_end, seq_id);
 	assert(key_buf_end < key_buf + key_buf_size);
 
-	struct credentials *orig_credentials = current_user();
+	struct credentials *orig_credentials = effective_user();
 	fiber_set_user(fiber(), &admin_credentials);
 
 	int rc = box_delete(BOX_SEQUENCE_DATA_ID, 0,
diff --git a/src/box/call.cc b/src/box/call.cc
index b5f4c4fa8a834489e98d7ecffc1c24781bb3229c..4d74160b0bebc066464f808c8568f04b88efcbbb 100644
--- a/src/box/call.cc
+++ b/src/box/call.cc
@@ -59,7 +59,7 @@ static inline int
 access_check_func(const char *name, uint32_t name_len, struct func **funcp)
 {
 	struct func *func = func_by_name(name, name_len);
-	struct credentials *credentials = current_user();
+	struct credentials *credentials = effective_user();
 	/*
 	 * If the user has universal access, don't bother with checks.
 	 * No special check for ADMIN user is necessary
@@ -191,7 +191,7 @@ box_process_call(struct call_request *request, struct obuf *out)
 	 */
 	struct credentials *orig_credentials = NULL;
 	if (func && func->def->setuid) {
-		orig_credentials = current_user();
+		orig_credentials = effective_user();
 		/* Remember and change the current user id. */
 		if (func->owner_credentials.auth_token >= BOX_USER_MAX) {
 			/*
diff --git a/src/box/lua/session.c b/src/box/lua/session.c
index 2538c543d5cbdc79512070f4bde975e6024593db..3238221ef4805eb3158a40ea60a8d5265368321d 100644
--- a/src/box/lua/session.c
+++ b/src/box/lua/session.c
@@ -101,7 +101,7 @@ lbox_session_sync(struct lua_State *L)
 
 /**
  * Session effective user id.
- * Note: user id (current_user()->uid)
+ * Note: user id (effective_user()->uid)
  * may be different in a setuid function.
  */
 static int
@@ -123,7 +123,7 @@ lbox_session_euid(struct lua_State *L)
 static int
 lbox_session_uid(struct lua_State *L)
 {
-	lua_pushnumber(L, current_user()->uid);
+	lua_pushnumber(L, effective_user()->uid);
 	return 1;
 }
 
@@ -135,7 +135,7 @@ lbox_session_uid(struct lua_State *L)
 static int
 lbox_session_user(struct lua_State *L)
 {
-	struct user *user = user_by_id(current_user()->uid);
+	struct user *user = user_by_id(effective_user()->uid);
 	if (user)
 		lua_pushstring(L, user->def->name);
 	else
@@ -179,6 +179,7 @@ lbox_session_su(struct lua_State *L)
 	/* sudo */
 	luaL_checktype(L, 2, LUA_TFUNCTION);
 	int error = lua_pcall(L, top - 2, LUA_MULTRET, 0);
+	/* Restore the original credentials. */
 	fiber_set_user(fiber(), &session->credentials);
 
 	if (error)
diff --git a/src/box/sequence.c b/src/box/sequence.c
index cd3ade659624f269b00035de3105c4358d3b3437..c7d7056dbd75d032ed9d8aaae5d75ca905deb8e6 100644
--- a/src/box/sequence.c
+++ b/src/box/sequence.c
@@ -241,7 +241,7 @@ sequence_next(struct sequence *seq, int64_t *result)
 int
 access_check_sequence(struct sequence *seq)
 {
-	struct credentials *cr = current_user();
+	struct credentials *cr = effective_user();
 	/*
 	 * If the user has universal access, don't bother with checks.
 	 * No special check for ADMIN user is necessary since ADMIN has
diff --git a/src/box/session.h b/src/box/session.h
index 6864c6e045acc0794182f4e8946a7c853d78023f..29efe2b0921deb0a0b7b7c31d15c744b38a1beab 100644
--- a/src/box/session.h
+++ b/src/box/session.h
@@ -87,7 +87,7 @@ struct session {
 	enum session_type type;
 	/** Authentication salt. */
 	char salt[SESSION_SEED_SIZE];
-	/** Cached user id and global grants */
+	/** Session user id and global grants */
 	struct credentials credentials;
 	/** Trigger for fiber on_stop to cleanup created on-demand session */
 	struct trigger fiber_on_stop;
@@ -184,7 +184,7 @@ current_session()
  * user on demand as in current_session() applies.
  */
 static inline struct credentials *
-current_user()
+effective_user()
 {
 	struct credentials *u =
 		(struct credentials *) fiber_get_key(fiber(),
@@ -247,7 +247,7 @@ session_run_on_auth_triggers(const char *user_name);
 static inline void
 access_check_universe(uint8_t access)
 {
-	struct credentials *credentials = current_user();
+	struct credentials *credentials = effective_user();
 	if (!(credentials->universal_access & access)) {
 		/*
 		 * Access violation, report error.
diff --git a/src/box/space.c b/src/box/space.c
index 703270361f4dde90e0223107eddf2f1fa90b941e..359728aaf0a944712c3497e49a52ec05ed3d367e 100644
--- a/src/box/space.c
+++ b/src/box/space.c
@@ -43,7 +43,7 @@
 int
 access_check_space(struct space *space, uint8_t access)
 {
-	struct credentials *cr = current_user();
+	struct credentials *cr = effective_user();
 	/*
 	 * If a user has a global permission, clear the respective
 	 * privilege from the list of privileges required
diff --git a/src/box/sysview_index.c b/src/box/sysview_index.c
index 27d3d55ee39e5ebbb54a4be5176ed4f5f87338ef..a76a67e444f20ea2701691179c06d8b555e2bcfe 100644
--- a/src/box/sysview_index.c
+++ b/src/box/sysview_index.c
@@ -183,7 +183,7 @@ static const struct index_vtab sysview_index_vtab = {
 static bool
 vspace_filter(struct space *source, struct tuple *tuple)
 {
-	struct credentials *cr = current_user();
+	struct credentials *cr = effective_user();
 	if (PRIV_R & cr->universal_access)
 		return true; /* read access to unverse */
 	if (PRIV_R & source->access[cr->auth_token].effective)
@@ -203,7 +203,7 @@ vspace_filter(struct space *source, struct tuple *tuple)
 static bool
 vuser_filter(struct space *source, struct tuple *tuple)
 {
-	struct credentials *cr = current_user();
+	struct credentials *cr = effective_user();
 	if (PRIV_R & cr->universal_access)
 		return true; /* read access to unverse */
 	if (PRIV_R & source->access[cr->auth_token].effective)
@@ -221,7 +221,7 @@ vuser_filter(struct space *source, struct tuple *tuple)
 static bool
 vpriv_filter(struct space *source, struct tuple *tuple)
 {
-	struct credentials *cr = current_user();
+	struct credentials *cr = effective_user();
 	if (PRIV_R & cr->universal_access)
 		return true; /* read access to unverse */
 	if (PRIV_R & source->access[cr->auth_token].effective)
@@ -239,7 +239,7 @@ vpriv_filter(struct space *source, struct tuple *tuple)
 static bool
 vfunc_filter(struct space *source, struct tuple *tuple)
 {
-	struct credentials *cr = current_user();
+	struct credentials *cr = effective_user();
 	if ((PRIV_R | PRIV_X) & cr->universal_access)
 		return true; /* read or execute access to unverse */
 	if (PRIV_R & source->access[cr->auth_token].effective)
diff --git a/src/box/user.cc b/src/box/user.cc
index d16695fbee48d1b2f80462ff840848013fd5bbf8..a0cbf4e981f716f10671ee4a652eea062d35d0be 100644
--- a/src/box/user.cc
+++ b/src/box/user.cc
@@ -242,7 +242,7 @@ access_find(struct priv_def *priv)
 static void
 user_set_effective_access(struct user *user)
 {
-	struct credentials *cr = current_user();
+	struct credentials *cr = effective_user();
 	struct privset_iterator it;
 	privset_ifirst(&user->privs, &it);
 	struct priv_def *priv;
diff --git a/test/box/access.result b/test/box/access.result
index ed8bf436496b08d05a56126a5a728d003ec48499..7072de75d3050acc144315cbbc7d5fb4643dfe84 100644
--- a/test/box/access.result
+++ b/test/box/access.result
@@ -908,3 +908,25 @@ box.schema.user.drop('test_user')
 box.schema.role.drop('test_role')
 ---
 ...
+-- gh-3023: box.session.su() changes both authenticated and effective
+-- user, while should only change the effective user
+--
+function uids() return { uid = box.session.uid(), euid = box.session.euid() } end
+---
+...
+box.session.su('guest')
+---
+...
+uids()
+---
+- uid: 0
+  euid: 0
+...
+box.session.su('admin')
+---
+...
+box.session.su('guest', uids)
+---
+- uid: 0
+  euid: 1
+...
diff --git a/test/box/access.test.lua b/test/box/access.test.lua
index 69217f6ba44b34d8a993923238f43dc81b462514..c353aad00ba117b2fa3b5c84e716ec45b9997e21 100644
--- a/test/box/access.test.lua
+++ b/test/box/access.test.lua
@@ -347,3 +347,12 @@ box.schema.role.info('test_role')
 
 box.schema.user.drop('test_user')
 box.schema.role.drop('test_role')
+
+-- gh-3023: box.session.su() changes both authenticated and effective
+-- user, while should only change the effective user
+--
+function uids() return { uid = box.session.uid(), euid = box.session.euid() } end
+box.session.su('guest')
+uids()
+box.session.su('admin')
+box.session.su('guest', uids)