diff --git a/changelogs/unreleased/gh-5799-add-info-to-fiber-object.md b/changelogs/unreleased/gh-5799-add-info-to-fiber-object.md
new file mode 100644
index 0000000000000000000000000000000000000000..3b5faad60b5e4cd555cde5756fcab4b56e7f58bc
--- /dev/null
+++ b/changelogs/unreleased/gh-5799-add-info-to-fiber-object.md
@@ -0,0 +1,4 @@
+## feature/lua/fiber
+
+* Introduce `fiber_object:info()` to get `info` from fiber. Works as `require(fiber).info()` but only for one fiber.
+* Introduce `fiber_object:csw()` to get `csw` from fiber (gh-5799).
diff --git a/src/lua/fiber.c b/src/lua/fiber.c
index 0800a1c269ea1a3ea3fa65b1a7e16df951150bdc..91898c283c29230b60f1c2bda7c3c877c18ef584 100644
--- a/src/lua/fiber.c
+++ b/src/lua/fiber.c
@@ -263,13 +263,10 @@ fiber_backtrace_cb(int frameno, void *frameret, const char *func, size_t offset,
 #endif
 
 static int
-lbox_fiber_statof(struct fiber *f, void *cb_ctx, bool backtrace)
+lbox_fiber_statof_map(struct fiber *f, void *cb_ctx, bool backtrace)
 {
 	struct lua_State *L = (struct lua_State *) cb_ctx;
 
-	luaL_pushuint64(L, f->fid);
-	lua_newtable(L);
-
 	lua_pushliteral(L, "name");
 	lua_pushstring(L, fiber_name(f));
 	lua_settable(L, -3);
@@ -313,6 +310,16 @@ lbox_fiber_statof(struct fiber *f, void *cb_ctx, bool backtrace)
 		lua_settable(L, -3);
 #endif /* ENABLE_BACKTRACE */
 	}
+	return 0;
+}
+
+static int
+lbox_fiber_statof(struct fiber *f, void *cb_ctx, bool backtrace)
+{
+	struct lua_State *L = cb_ctx;
+	luaL_pushuint64(L, f->fid);
+	lua_newtable(L);
+	lbox_fiber_statof_map(f, cb_ctx, backtrace);
 	lua_settable(L, -3);
 	return 0;
 }
@@ -406,14 +413,10 @@ lbox_fiber_top_disable(struct lua_State *L)
 }
 #endif /* ENABLE_FIBER_TOP */
 
-/**
- * Return fiber statistics.
- */
-static int
-lbox_fiber_info(struct lua_State *L)
-{
 #ifdef ENABLE_BACKTRACE
-	bool do_backtrace = true;
+bool
+lbox_do_backtrace(struct lua_State *L)
+{
 	if (lua_istable(L, 1)) {
 		lua_pushstring(L, "backtrace");
 		lua_gettable(L, 1);
@@ -423,9 +426,21 @@ lbox_fiber_info(struct lua_State *L)
 			lua_gettable(L, 1);
 		}
 		if (!lua_isnil(L, -1))
-			do_backtrace = lua_toboolean(L, -1);
+			return lua_toboolean(L, -1);
 		lua_pop(L, 1);
 	}
+	return true;
+}
+#endif /* ENABLE_BACKTRACE */
+
+/**
+ * Return fiber statistics.
+ */
+static int
+lbox_fiber_info(struct lua_State *L)
+{
+#ifdef ENABLE_BACKTRACE
+	bool do_backtrace = lbox_do_backtrace(L);
 	if (do_backtrace) {
 		lua_newtable(L);
 		fiber_stat(lbox_fiber_statof_bt, L);
@@ -527,6 +542,17 @@ lbox_fiber_new(struct lua_State *L)
 	return 1;
 }
 
+static struct fiber *
+lbox_get_fiber(struct lua_State *L)
+{
+	if (lua_gettop(L) != 0) {
+		uint64_t *fid = luaL_checkudata(L, 1, fiberlib_name);
+		return fiber_find(*fid);
+	} else {
+		return fiber();
+	}
+}
+
 /**
  * Get fiber status.
  * This follows the rules of Lua coroutine.status() function:
@@ -540,16 +566,9 @@ lbox_fiber_new(struct lua_State *L)
 static int
 lbox_fiber_status(struct lua_State *L)
 {
-	struct fiber *f;
-	if (lua_gettop(L)) {
-		uint64_t fid = *(uint64_t *)
-			luaL_checkudata(L, 1, fiberlib_name);
-		f = fiber_find(fid);
-	} else {
-		f = fiber();
-	}
+	struct fiber *f = lbox_get_fiber(L);
 	const char *status;
-	if (f == NULL || f->fid == 0) {
+	if (f == NULL) {
 		/* This fiber is dead. */
 		status = "dead";
 	} else if (f == fiber()) {
@@ -563,6 +582,42 @@ lbox_fiber_status(struct lua_State *L)
 	return 1;
 }
 
+/**
+ * Get fiber info: number of context switches, backtrace, id,
+ * total memory, used memory.
+ */
+static int
+lbox_fiber_object_info(struct lua_State *L)
+{
+	struct fiber *f = lbox_get_fiber(L);
+	if (f == NULL)
+		luaL_error(L, "the fiber is dead");
+#ifdef ENABLE_BACKTRACE
+	bool do_backtrace = lbox_do_backtrace(L);
+	if (do_backtrace) {
+		lua_newtable(L);
+		lbox_fiber_statof_map(f, L, true);
+	} else
+#endif /* ENABLE_BACKTRACE */
+	{
+		lua_newtable(L);
+		lbox_fiber_statof_map(f, L, false);
+	}
+	return 1;
+}
+
+static int
+lbox_fiber_csw(struct lua_State *L)
+{
+	struct fiber *f = lbox_get_fiber(L);
+	if (f == NULL) {
+		luaL_error(L, "the fiber is dead");
+	} else {
+		lua_pushinteger(L, f->csw);
+	}
+	return 1;
+}
+
 /**
  * Get or set fiber name.
  * With no arguments, gets or sets the current fiber
@@ -857,6 +912,8 @@ static const struct luaL_Reg lbox_fiber_meta [] = {
 	{"name", lbox_fiber_name},
 	{"cancel", lbox_fiber_cancel},
 	{"status", lbox_fiber_status},
+	{"info", lbox_fiber_object_info},
+	{"csw", lbox_fiber_csw},
 	{"testcancel", lbox_fiber_testcancel},
 	{"__serialize", lbox_fiber_serialize},
 	{"__tostring", lbox_fiber_tostring},
diff --git a/test/app/gh-5799-fiber-info.result b/test/app/gh-5799-fiber-info.result
new file mode 100644
index 0000000000000000000000000000000000000000..716ac9a246527b4706bf9b47da423911c968c02f
--- /dev/null
+++ b/test/app/gh-5799-fiber-info.result
@@ -0,0 +1,80 @@
+-- test-run result file version 2
+test_run = require('test_run').new()
+ | ---
+ | ...
+fiber = require('fiber')
+ | ---
+ | ...
+json = require('json')
+ | ---
+ | ...
+
+function yielder(n) for i=1, n do fiber.yield() end end
+ | ---
+ | ...
+
+csw_check_counter = 0
+ | ---
+ | ...
+fibers = {}
+ | ---
+ | ...
+
+test_run:cmd('setopt delimiter ";"')
+ | ---
+ | - true
+ | ...
+for i=1,100 do
+    fibers[i] = fiber.new(function()
+        local start_csw = fiber.info()[fiber.self():id()].csw
+        for j=1,10 do
+            fiber.yield()
+            if j + start_csw == fiber.self():csw() and
+               j + start_csw == fiber.self():info().csw then
+                csw_check_counter = csw_check_counter + 1
+            end
+        end
+    end)
+    fibers[i]:set_joinable(true)
+end;
+ | ---
+ | ...
+for i=1,100 do
+    fibers[i]:join()
+end;
+ | ---
+ | ...
+test_run:cmd('setopt delimiter ""');
+ | ---
+ | - true
+ | ...
+csw_check_counter
+ | ---
+ | - 1000
+ | ...
+
+cond = fiber.cond()
+ | ---
+ | ...
+running = fiber.create(function() cond:wait() end)
+ | ---
+ | ...
+json.encode(running:info()) == json.encode(fiber.info()[running:id()])
+ | ---
+ | - true
+ | ...
+cond:signal()
+ | ---
+ | ...
+dead = fiber.create(function() end)
+ | ---
+ | ...
+
+dead:csw()
+ | ---
+ | - error: the fiber is dead
+ | ...
+dead:info()
+ | ---
+ | - error: the fiber is dead
+ | ...
diff --git a/test/app/gh-5799-fiber-info.test.lua b/test/app/gh-5799-fiber-info.test.lua
new file mode 100644
index 0000000000000000000000000000000000000000..588f760c40c8918f0184dac3ceb5b3508f1590bc
--- /dev/null
+++ b/test/app/gh-5799-fiber-info.test.lua
@@ -0,0 +1,37 @@
+test_run = require('test_run').new()
+fiber = require('fiber')
+json = require('json')
+
+function yielder(n) for i=1, n do fiber.yield() end end
+
+csw_check_counter = 0
+fibers = {}
+
+test_run:cmd('setopt delimiter ";"')
+for i=1,100 do
+    fibers[i] = fiber.new(function()
+        local start_csw = fiber.info()[fiber.self():id()].csw
+        for j=1,10 do
+            fiber.yield()
+            if j + start_csw == fiber.self():csw() and
+               j + start_csw == fiber.self():info().csw then
+                csw_check_counter = csw_check_counter + 1
+            end
+        end
+    end)
+    fibers[i]:set_joinable(true)
+end;
+for i=1,100 do
+    fibers[i]:join()
+end;
+test_run:cmd('setopt delimiter ""');
+csw_check_counter
+
+cond = fiber.cond()
+running = fiber.create(function() cond:wait() end)
+json.encode(running:info()) == json.encode(fiber.info()[running:id()])
+cond:signal()
+dead = fiber.create(function() end)
+
+dead:csw()
+dead:info()