diff --git a/crates/curp/src/server/conflict/mod.rs b/crates/curp/src/server/conflict/mod.rs
index 87aa31d27..67c3f426b 100644
--- a/crates/curp/src/server/conflict/mod.rs
+++ b/crates/curp/src/server/conflict/mod.rs
@@ -101,6 +101,20 @@ impl<C> PartialEq for CommandEntry<C> {
 
 impl<C> Eq for CommandEntry<C> {}
 
+impl<C> PartialOrd for CommandEntry<C> {
+    #[inline]
+    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl<C> Ord for CommandEntry<C> {
+    #[inline]
+    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
+        self.id.cmp(&other.id)
+    }
+}
+
 impl<C> From<CommandEntry<C>> for PoolEntry<C> {
     fn from(entry: CommandEntry<C>) -> Self {
         PoolEntry {
diff --git a/crates/xline/src/conflict/tests.rs b/crates/xline/src/conflict/tests.rs
index 886b3b1eb..5a003b39e 100644
--- a/crates/xline/src/conflict/tests.rs
+++ b/crates/xline/src/conflict/tests.rs
@@ -28,7 +28,10 @@ fn kv_sp_operations_are_ok() {
     assert!(sp.insert_if_not_conflict(entry2.clone()).is_none());
     assert!(sp.insert_if_not_conflict(entry3.clone()).is_some());
     assert!(sp.insert_if_not_conflict(entry4.clone()).is_none());
-    assert_eq!(sp.all().len(), 3);
+    compare_commands(
+        sp.all(),
+        vec![entry1.clone(), entry2.clone(), entry4.clone()],
+    );
     assert_eq!(sp.len(), 3);
     sp.remove(entry1.clone());
     assert!(sp.insert_if_not_conflict(entry3.clone()).is_some());
@@ -56,10 +59,25 @@ fn kv_ucp_operations_are_ok() {
     assert!(!ucp.insert(entry3.clone()));
     assert!(ucp.insert(entry4.clone()));
     assert!(ucp.insert(entry5.clone()));
-    assert_eq!(ucp.all().len(), 5);
+    compare_commands(
+        ucp.all(),
+        vec![
+            entry1.clone(),
+            entry2.clone(),
+            entry3.clone(),
+            entry4.clone(),
+            entry5.clone(),
+        ],
+    );
     assert_eq!(ucp.len(), 5);
-    assert_eq!(ucp.all_conflict(&entry1).len(), 3);
-    assert_eq!(ucp.all_conflict(&entry6).len(), 2);
+    compare_commands(
+        ucp.all_conflict(&entry1),
+        vec![entry1.clone(), entry2.clone(), entry4.clone()],
+    );
+    compare_commands(
+        ucp.all_conflict(&entry6),
+        vec![entry4.clone(), entry5.clone()],
+    );
     ucp.remove(entry4.clone());
     ucp.remove(entry5.clone());
     assert!(!ucp.insert(entry6.clone()));
@@ -81,7 +99,7 @@ fn lease_sp_operations_are_ok() {
     assert!(sp.insert_if_not_conflict(entry2.clone()).is_none());
     assert!(sp.insert_if_not_conflict(entry3.clone()).is_some());
     assert!(sp.insert_if_not_conflict(entry4.clone()).is_some());
-    assert_eq!(sp.all().len(), 2);
+    compare_commands(sp.all(), vec![entry1.clone(), entry2.clone()]);
     assert_eq!(sp.len(), 2);
     sp.remove(entry1);
     sp.remove(entry2);
@@ -106,10 +124,25 @@ fn lease_ucp_operations_are_ok() {
     assert!(!ucp.insert(entry3.clone()));
     assert!(ucp.insert(entry4.clone()));
     assert!(ucp.insert(entry5.clone()));
-    assert_eq!(ucp.all().len(), 5);
+    compare_commands(
+        ucp.all(),
+        vec![
+            entry1.clone(),
+            entry2.clone(),
+            entry3.clone(),
+            entry4.clone(),
+            entry5.clone(),
+        ],
+    );
     assert_eq!(ucp.len(), 5);
-    assert_eq!(ucp.all_conflict(&entry1).len(), 3);
-    assert_eq!(ucp.all_conflict(&entry3).len(), 2);
+    compare_commands(
+        ucp.all_conflict(&entry1),
+        vec![entry1.clone(), entry2.clone(), entry4.clone()],
+    );
+    compare_commands(
+        ucp.all_conflict(&entry3),
+        vec![entry3.clone(), entry5.clone()],
+    );
     ucp.remove(entry3.clone());
     ucp.remove(entry5.clone());
     assert!(!ucp.insert(entry5.clone()));
@@ -127,7 +160,7 @@ fn exclusive_sp_operations_are_ok() {
     assert!(sp.insert_if_not_conflict(entry1.clone()).is_some());
     assert!(sp.insert_if_not_conflict(entry1.clone()).is_some());
     assert!(sp.insert_if_not_conflict(entry2.clone()).is_some());
-    assert_eq!(sp.all().len(), 1);
+    compare_commands(sp.all(), vec![entry1.clone()]);
     assert_eq!(sp.len(), 1);
     sp.remove(entry1);
     assert!(sp.insert_if_not_conflict(entry2).is_some());
@@ -144,8 +177,11 @@ fn exclusive_ucp_operations_are_ok() {
     let entry2 = gen.gen_role_add();
     assert!(ucp.insert(entry1.clone()));
     assert!(ucp.insert(entry2.clone()));
-    assert_eq!(ucp.all().len(), 2);
-    assert_eq!(ucp.all_conflict(&entry1).len(), 2);
+    compare_commands(ucp.all(), vec![entry1.clone(), entry2.clone()]);
+    compare_commands(
+        ucp.all_conflict(&entry1),
+        vec![entry1.clone(), entry2.clone()],
+    );
     assert_eq!(ucp.len(), 2);
     ucp.remove(entry1.clone());
     ucp.remove(entry2.clone());
@@ -155,6 +191,12 @@ fn exclusive_ucp_operations_are_ok() {
     assert_eq!(ucp.len(), 0);
 }
 
+fn compare_commands(mut a: Vec<CommandEntry<Command>>, mut b: Vec<CommandEntry<Command>>) {
+    a.sort_unstable();
+    b.sort_unstable();
+    assert_eq!(a, b);
+}
+
 #[derive(Default)]
 struct EntryGenerator {
     id: u64,
diff --git a/crates/xlineapi/src/command.rs b/crates/xlineapi/src/command.rs
index fddca5159..f51169b45 100644
--- a/crates/xlineapi/src/command.rs
+++ b/crates/xlineapi/src/command.rs
@@ -209,8 +209,7 @@ impl From<KeyRange> for PbKeyRange {
 }
 
 /// Command to run consensus protocol
-#[cfg_attr(test, derive(PartialEq))]
-#[derive(Clone, Debug, Serialize, Deserialize)]
+#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
 pub struct Command {
     /// Request data
     request: RequestWrapper,