diff --git a/libcxx/docs/Status/SpaceshipProjects.csv b/libcxx/docs/Status/SpaceshipProjects.csv
--- a/libcxx/docs/Status/SpaceshipProjects.csv
+++ b/libcxx/docs/Status/SpaceshipProjects.csv
@@ -78,4 +78,4 @@
 | `[fs.path.nonmember] <https://wg21.link/fs.path.nonmember>`_,| `filesystem::path <https://reviews.llvm.org/D130859>`_,None,Adrian Vogelsgesang,|In Progress|
 | `[fs.dir.entry.obs] <https://wg21.link/fs.dir.entry.obs>`_,| `filesystem::directory_entry <https://reviews.llvm.org/D130860>`_,None,Adrian Vogelsgesang,|In Progress|
 | `[re.submatch.op] <https://wg21.link/re.submatch.op>`_,| sub_match,None,Mark de Wever,|In Progress|
-| `[thread.thread.id] <https://wg21.link/thread.thread.id>`_,| thread::id,None,Unassigned,|Not Started|
+| `[thread.thread.id] <https://wg21.link/thread.thread.id>`_,| `thread::id <https://reviews.llvm.org/D131362>`_,None,Adrian Vogelsgesang,|Complete|
diff --git a/libcxx/include/__threading_support b/libcxx/include/__threading_support
--- a/libcxx/include/__threading_support
+++ b/libcxx/include/__threading_support
@@ -13,6 +13,7 @@
 #include <__availability>
 #include <__chrono/convert_to_timespec.h>
 #include <__chrono/duration.h>
+#include <__compare/ordering.h>
 #include <__config>
 #include <__thread/poll_with_backoff.h>
 #include <errno.h>
@@ -609,27 +610,34 @@
     // on other platforms.  We assume 0 works everywhere for now.
     __libcpp_thread_id __id_;
 
+    static _LIBCPP_INLINE_VISIBILITY
+        bool __eq_impl(__thread_id __x, __thread_id __y) _NOEXCEPT
+        { // don't pass id==0 to underlying routines
+        if (__x.__id_ == 0) return __y.__id_ == 0;
+        if (__y.__id_ == 0) return false;
+        return __libcpp_thread_id_equal(__x.__id_, __y.__id_);
+        }
+    static _LIBCPP_INLINE_VISIBILITY
+        bool __lt_impl(__thread_id __x, __thread_id __y) _NOEXCEPT
+        { // id==0 is always less than any other thread_id
+        if (__x.__id_ == 0) return __y.__id_ != 0;
+        if (__y.__id_ == 0) return false;
+        return  __libcpp_thread_id_less(__x.__id_, __y.__id_);
+        }
 public:
     _LIBCPP_INLINE_VISIBILITY
     __thread_id() _NOEXCEPT : __id_(0) {}
 
     friend _LIBCPP_INLINE_VISIBILITY
         bool operator==(__thread_id __x, __thread_id __y) _NOEXCEPT
-        { // don't pass id==0 to underlying routines
-        if (__x.__id_ == 0) return __y.__id_ == 0;
-        if (__y.__id_ == 0) return false;
-        return __libcpp_thread_id_equal(__x.__id_, __y.__id_);
-        }
+        {return __eq_impl(__x, __y);}
+#if _LIBCPP_STD_VER <= 17
     friend _LIBCPP_INLINE_VISIBILITY
         bool operator!=(__thread_id __x, __thread_id __y) _NOEXCEPT
         {return !(__x == __y);}
     friend _LIBCPP_INLINE_VISIBILITY
         bool operator< (__thread_id __x, __thread_id __y) _NOEXCEPT
-        { // id==0 is always less than any other thread_id
-        if (__x.__id_ == 0) return __y.__id_ != 0;
-        if (__y.__id_ == 0) return false;
-        return  __libcpp_thread_id_less(__x.__id_, __y.__id_);
-        }
+        {return __lt_impl(__x, __y);}
     friend _LIBCPP_INLINE_VISIBILITY
         bool operator<=(__thread_id __x, __thread_id __y) _NOEXCEPT
         {return !(__y < __x);}
@@ -639,6 +647,15 @@
     friend _LIBCPP_INLINE_VISIBILITY
         bool operator>=(__thread_id __x, __thread_id __y) _NOEXCEPT
         {return !(__x < __y);}
+#else // _LIBCPP_STD_VER <= 17
+    friend _LIBCPP_INLINE_VISIBILITY
+        strong_ordering operator<=>(__thread_id __x, __thread_id __y) noexcept
+        {
+           if (__eq_impl(__x, __y)) return strong_ordering::equal;
+           if (__lt_impl(__x, __y)) return strong_ordering::less;
+           return strong_ordering::greater;
+        }
+#endif // _LIBCPP_STD_VER <= 17
 
     _LIBCPP_INLINE_VISIBILITY
     void __reset() { __id_ = 0; }
diff --git a/libcxx/include/thread b/libcxx/include/thread
--- a/libcxx/include/thread
+++ b/libcxx/include/thread
@@ -53,11 +53,12 @@
 };
 
 bool operator==(thread::id x, thread::id y) noexcept;
-bool operator!=(thread::id x, thread::id y) noexcept;
-bool operator< (thread::id x, thread::id y) noexcept;
-bool operator<=(thread::id x, thread::id y) noexcept;
-bool operator> (thread::id x, thread::id y) noexcept;
-bool operator>=(thread::id x, thread::id y) noexcept;
+bool operator!=(thread::id x, thread::id y) noexcept;             // removed in C++20
+bool operator< (thread::id x, thread::id y) noexcept;             // removed in C++20
+bool operator<=(thread::id x, thread::id y) noexcept;             // removed in C++20
+bool operator> (thread::id x, thread::id y) noexcept;             // removed in C++20
+bool operator>=(thread::id x, thread::id y) noexcept;             // removed in C++20
+strong_ordering operator<=>(thread::id x, thread::id y) noexcept; // C++20
 
 template<class charT, class traits>
 basic_ostream<charT, traits>&
diff --git a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/cmp.pass.cpp b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/cmp.pass.cpp
new file mode 100644
--- /dev/null
+++ b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/cmp.pass.cpp
@@ -0,0 +1,55 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// UNSUPPORTED: no-threads
+
+// <thread>
+
+// class thread::id
+
+// bool operator==(thread::id x, thread::id y) noexcept;
+// bool operator!=(thread::id x, thread::id y) noexcept;
+// bool operator< (thread::id x, thread::id y) noexcept;
+// bool operator<=(thread::id x, thread::id y) noexcept;
+// bool operator> (thread::id x, thread::id y) noexcept;
+// bool operator>=(thread::id x, thread::id y) noexcept;
+// strong_ordering operator<=>(thread::id x, thread::id y) noexcept;
+
+#include <thread>
+#include <cassert>
+
+#include "test_macros.h"
+#include "test_comparisons.h"
+
+int main(int, char**) {
+  AssertComparisonsAreNoexcept<std::thread::id>();
+  AssertComparisonsReturnBool<std::thread::id>();
+#if TEST_STD_VER > 17
+  AssertOrderAreNoexcept<std::thread::id>();
+  AssertOrderReturn<std::strong_ordering, std::thread::id>();
+#endif
+
+  std::thread::id id1;
+  std::thread::id id2;
+  std::thread::id id3 = std::this_thread::get_id();
+
+  // `id1` and `id2` should compare equal
+  assert(testComparisons(id1, id2, /*isEqual*/ true, /*isLess*/ false));
+#if TEST_STD_VER > 17
+  assert(testOrder(id1, id2, std::strong_ordering::equal));
+#endif
+
+  // Test `t1` and `t3` which are not equal
+  bool isLess = id1 < id3;
+  assert(testComparisons(id1, id3, /*isEqual*/ false, isLess));
+#if TEST_STD_VER > 17
+  assert(testOrder(id1, id3, isLess ? std::strong_ordering::less : std::strong_ordering::greater));
+#endif
+
+  return 0;
+}
diff --git a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/eq.pass.cpp b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/eq.pass.cpp
deleted file mode 100644
--- a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/eq.pass.cpp
+++ /dev/null
@@ -1,35 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// UNSUPPORTED: no-threads
-
-// <thread>
-
-// class thread::id
-
-// bool operator==(thread::id x, thread::id y);
-// bool operator!=(thread::id x, thread::id y);
-
-#include <thread>
-#include <cassert>
-
-#include "test_macros.h"
-
-int main(int, char**)
-{
-    std::thread::id id0;
-    std::thread::id id1;
-    id1 = id0;
-    assert( (id1 == id0));
-    assert(!(id1 != id0));
-    id1 = std::this_thread::get_id();
-    assert(!(id1 == id0));
-    assert( (id1 != id0));
-
-  return 0;
-}
diff --git a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/lt.pass.cpp b/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/lt.pass.cpp
deleted file mode 100644
--- a/libcxx/test/std/thread/thread.threads/thread.thread.class/thread.thread.id/lt.pass.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// UNSUPPORTED: no-threads
-
-// <thread>
-
-// class thread::id
-
-// bool operator< (thread::id x, thread::id y);
-// bool operator<=(thread::id x, thread::id y);
-// bool operator> (thread::id x, thread::id y);
-// bool operator>=(thread::id x, thread::id y);
-
-#include <thread>
-#include <cassert>
-
-#include "test_macros.h"
-
-int main(int, char**)
-{
-    std::thread::id id0;
-    std::thread::id id1;
-    std::thread::id id2 = std::this_thread::get_id();
-    assert(!(id0 <  id1));
-    assert( (id0 <= id1));
-    assert(!(id0 >  id1));
-    assert( (id0 >= id1));
-    assert(!(id0 == id2));
-    if (id0 < id2) {
-      assert( (id0 <= id2));
-      assert(!(id0 >  id2));
-      assert(!(id0 >= id2));
-    } else {
-      assert(!(id0 <= id2));
-      assert( (id0 >  id2));
-      assert( (id0 >= id2));
-    }
-
-  return 0;
-}