diff --git a/changelogs/unreleased/gh-10196-fix-fiber-self-join-hang.md b/changelogs/unreleased/gh-10196-fix-fiber-self-join-hang.md
new file mode 100644
index 0000000000000000000000000000000000000000..872c3f4531673a79ee3e8f130babfa90427b6d65
--- /dev/null
+++ b/changelogs/unreleased/gh-10196-fix-fiber-self-join-hang.md
@@ -0,0 +1,3 @@
+## bugfix/core
+
+* Fixed hang on fiber self join (gh-10196).
diff --git a/src/lib/core/fiber.c b/src/lib/core/fiber.c
index cfc00ab741aa2bd6bdf23ac03306e5f3caca87b9..b5782d9784db9de7a449280e55d7b42a6acbaeb2 100644
--- a/src/lib/core/fiber.c
+++ b/src/lib/core/fiber.c
@@ -764,6 +764,9 @@ fiber_join_timeout(struct fiber *fiber, double timeout)
 	if ((fiber->flags & FIBER_JOIN_BEEN_INVOKED) != 0)
 		panic("join of a joined fiber detected");
 
+	if (fiber() == fiber)
+		panic("cannot join itself");
+
 	/* Prohibit joining the fiber and changing its joinability. */
 	fiber->flags |= FIBER_JOIN_BEEN_INVOKED;
 
diff --git a/src/lib/core/fiber.h b/src/lib/core/fiber.h
index c1e67c38587c6ea133f92bebf4ce042591251f77..959d084fb0c84902975a15ae1f6c17af3f3c0cd6 100644
--- a/src/lib/core/fiber.h
+++ b/src/lib/core/fiber.h
@@ -366,6 +366,7 @@ fiber_set_joinable(struct fiber *fiber, bool yesno);
  *
  * @pre FIBER_IS_JOINABLE flag is set (panic if not).
  * @pre the fiber is not joined yet (panic if not).
+ * @pre the fiber is different from current (panic if not).
  *
  * \param f fiber to be woken up
  * \return fiber function ret code
diff --git a/src/lua/fiber.c b/src/lua/fiber.c
index abe0c4efa41e7ffa0f074b6b5cbe2066c00fb74d..3a922eaf8bc20494954fea61f3a301d0d411dcc9 100644
--- a/src/lua/fiber.c
+++ b/src/lua/fiber.c
@@ -811,6 +811,8 @@ lbox_fiber_join(struct lua_State *L)
 
 	if (!(fiber->flags & FIBER_IS_JOINABLE))
 		luaL_error(L, "the fiber is not joinable");
+	if (fid == fiber()->fid)
+		luaL_error(L, "cannot join itself");
 	double timeout = TIMEOUT_INFINITY;
 	if (!lua_isnoneornil(L, 2)) {
 		if (!lua_isnumber(L, 2) ||
diff --git a/test/app-luatest/fiber_test.lua b/test/app-luatest/fiber_test.lua
index 4aa262617e33f58cf5f4107eb3002527268d13f1..55fd621e2660867315510c29df875fb7c51ef439 100644
--- a/test/app-luatest/fiber_test.lua
+++ b/test/app-luatest/fiber_test.lua
@@ -81,3 +81,15 @@ g.test_gh_10187_no_memory_leak_on_dead_fiber_search = function()
     collectgarbage()
     t.assert_equals(weak_table.fiber, nil)
 end
+
+g.test_gh_10196_no_hang_on_self_join = function()
+    local f = fiber.new(function()
+        fiber.self():join()
+    end)
+    f:set_joinable(true)
+    f:wakeup()
+    fiber.yield()
+    local ok, res = f:join()
+    t.assert_not(ok)
+    t.assert_error_msg_contains('cannot join itself', box.error, res)
+end