diff --git a/changelogs/unreleased/gh-9406-fix-use-after-free-on-shutdown.md b/changelogs/unreleased/gh-9406-fix-use-after-free-on-shutdown.md
new file mode 100644
index 0000000000000000000000000000000000000000..b5f58bc4b248060cae1d75944095ec99128dc5b6
--- /dev/null
+++ b/changelogs/unreleased/gh-9406-fix-use-after-free-on-shutdown.md
@@ -0,0 +1,4 @@
+## bugfix/core
+
+* Fixed potential use-after-free on Tarantool shutdown with lingering
+  fiber join (gh-9406).
diff --git a/src/lib/core/fiber.c b/src/lib/core/fiber.c
index 5fa2be21265b7ac46d5d1ce7f441fa17f1a04a83..fa0f02abfc4c6ded096be3e1e789a57f630e1457 100644
--- a/src/lib/core/fiber.c
+++ b/src/lib/core/fiber.c
@@ -1637,6 +1637,7 @@ fiber_destroy(struct cord *cord, struct fiber *f)
 	trigger_destroy(&f->on_stop);
 	rlist_del(&f->state);
 	rlist_del(&f->link);
+	rlist_del(&f->wake);
 #ifdef ENABLE_BACKTRACE
 	region_set_callbacks(&f->gc, NULL, NULL, NULL);
 #endif
@@ -1825,6 +1826,7 @@ cord_create(struct cord *cord, const char *name)
 	/* sched fiber is not present in alive/ready/dead list. */
 	rlist_create(&cord->sched.state);
 	rlist_create(&cord->sched.link);
+	rlist_create(&cord->sched.wake);
 	cord->sched.fid = FIBER_ID_SCHED;
 	fiber_reset(&cord->sched);
 	diag_create(&cord->sched.diag);
diff --git a/test/app-luatest/fiber_test.lua b/test/app-luatest/fiber_test.lua
index f42cfb62c9fe9e7c3e1799c55a6d4f7fa445d8b2..8a681b48ed89534f73486a560d7732f96ca23aba 100644
--- a/test/app-luatest/fiber_test.lua
+++ b/test/app-luatest/fiber_test.lua
@@ -34,3 +34,26 @@ g.test_tostring = function()
     fiber.yield()
     t.assert_equals(tostring(f), "fiber: " .. fid .. " (dead)")
 end
+
+g.test_gh_9406_shutdown_with_lingering_fiber_join = function()
+    local script = [[
+        local fiber = require('fiber')
+
+        local f = nil
+        fiber.create(function()
+            while f == nil do
+                fiber.sleep(0.1)
+            end
+            fiber.join(f)
+        end)
+        f = fiber.new(function()
+            fiber.sleep(1000)
+        end)
+        f:set_joinable(true)
+        fiber.sleep(0.2)
+        os.exit()
+    ]]
+    local tarantool_bin = arg[-1]
+    local cmd = string.format('%s -e "%s"', tarantool_bin, script)
+    t.assert(os.execute(cmd) == 0)
+end