diff --git a/src/executor/AddHostsExecutor.cpp b/src/executor/AddHostsExecutor.cpp
index 0de89379bc07c9d27bb067856d55e842b45f83ee..3ced55e3b1603c6f3802089399a9594085b81b00 100644
--- a/src/executor/AddHostsExecutor.cpp
+++ b/src/executor/AddHostsExecutor.cpp
@@ -31,10 +31,10 @@ void AddHostsExecutor::execute() {
     auto cb = [this] (auto &&resp) {
         if (!resp.ok()) {
             DCHECK(onError_);
-            onError_(resp.status());
+            onError_(std::move(resp).status());
             return;
         }
-        auto ret = resp.value();
+        auto ret = std::move(resp).value();
         if (!ret) {
             DCHECK(onError_);
             onError_(Status::Error("Add hosts failed"));
diff --git a/src/executor/CreateSpaceExecutor.cpp b/src/executor/CreateSpaceExecutor.cpp
index 5d701fdb4822f9f5dea96a2e8d0e0499f422c8d6..338b3d3f5b53e306f45c3b59a231ce466015a020 100644
--- a/src/executor/CreateSpaceExecutor.cpp
+++ b/src/executor/CreateSpaceExecutor.cpp
@@ -44,10 +44,10 @@ void CreateSpaceExecutor::execute() {
     auto cb = [this] (auto &&resp) {
         if (!resp.ok()) {
             DCHECK(onError_);
-            onError_(resp.status());
+            onError_(std::move(resp).status());
             return;
         }
-        auto spaceId = resp.value();
+        auto spaceId = std::move(resp).value();
         if (spaceId <= 0) {
             DCHECK(onError_);
             onError_(Status::Error("Create space failed"));
diff --git a/src/executor/DropSpaceExecutor.cpp b/src/executor/DropSpaceExecutor.cpp
index 15cb5866d2b0d551e7b62fb047ecf3bc92a25638..ceabb3dcc47c27a6054710988d3a2f5f436114c7 100644
--- a/src/executor/DropSpaceExecutor.cpp
+++ b/src/executor/DropSpaceExecutor.cpp
@@ -28,10 +28,10 @@ void DropSpaceExecutor::execute() {
     auto cb = [this] (auto &&resp) {
         if (!resp.ok()) {
             DCHECK(onError_);
-            onError_(resp.status());
+            onError_(std::move(resp).status());
             return;
         }
-        auto  ret = resp.value();
+        auto  ret = std::move(resp).value();
         if (!ret) {
             DCHECK(onError_);
             onError_(Status::Error("Drop space failed"));
diff --git a/src/executor/RemoveHostsExecutor.cpp b/src/executor/RemoveHostsExecutor.cpp
index 8efc3bc1fce04c767927a64f388146801dc081d9..711c79ee1ce727fa94b2afda81960f07343f9e32 100644
--- a/src/executor/RemoveHostsExecutor.cpp
+++ b/src/executor/RemoveHostsExecutor.cpp
@@ -31,10 +31,10 @@ void RemoveHostsExecutor::execute() {
     auto cb = [this] (auto &&resp) {
         if (!resp.ok()) {
             DCHECK(onError_);
-            onError_(resp.status());
+            onError_(std::move(resp).status());
             return;
         }
-        auto ret = resp.value();
+        auto ret = std::move(resp).value();
         if (!ret) {
             DCHECK(onError_);
             onError_(Status::Error("Remove hosts failed"));
diff --git a/src/executor/ShowExecutor.cpp b/src/executor/ShowExecutor.cpp
index de58e82130b70f41d0d280d0571e5f361d94b8bf..68846a63f9b8ce36bf70269a55b46fae19a3386f 100644
--- a/src/executor/ShowExecutor.cpp
+++ b/src/executor/ShowExecutor.cpp
@@ -29,6 +29,9 @@ void ShowExecutor::execute() {
         case ShowSentence::ShowType::kShowHosts:
             showHosts();
             break;
+        case ShowSentence::ShowType::kShowSpaces:
+            showSpaces();
+            break;
         case ShowSentence::ShowType::kUnknown:
             onError_(Status::Error("Type unknown"));
             break;
@@ -44,23 +47,21 @@ void ShowExecutor::showHosts() {
     auto cb = [this] (auto &&resp) {
         if (!resp.ok()) {
             DCHECK(onError_);
-            onError_(resp.status());
+            onError_(std::move(resp).status());
             return;
         }
 
-        auto retShowHosts = resp.value();
+        auto retShowHosts = std::move(resp).value();
         std::vector<cpp2::RowValue> rows;
-        std::vector<cpp2::ColumnValue> row;
         std::vector<std::string> header;
         resp_ = std::make_unique<cpp2::ExecutionResponse>();
 
-        header.clear();
         header.push_back("Ip");
         header.push_back("Port");
         resp_->set_column_names(std::move(header));
 
         for (auto &host : retShowHosts) {
-            row.clear();
+            std::vector<cpp2::ColumnValue> row;
             row.resize(2);
             row[0].set_str(NetworkUtils::ipFromHostAddr(host));
             row[1].set_str(folly::to<std::string>(NetworkUtils::portFromHostAddr(host)));
@@ -84,6 +85,48 @@ void ShowExecutor::showHosts() {
 }
 
 
+void ShowExecutor::showSpaces() {
+    auto future = ectx()->getMetaClient()->listSpaces();
+    auto *runner = ectx()->rctx()->runner();
+
+    auto cb = [this] (auto &&resp) {
+        if (!resp.ok()) {
+            DCHECK(onError_);
+            onError_(std::move(resp).status());
+            return;
+        }
+
+        auto retShowSpaces = std::move(resp).value();
+        std::vector<cpp2::RowValue> rows;
+        std::vector<std::string> header;
+        resp_ = std::make_unique<cpp2::ExecutionResponse>();
+
+        header.push_back("Name");
+        resp_->set_column_names(std::move(header));
+
+        for (auto &space : retShowSpaces) {
+            std::vector<cpp2::ColumnValue> row;
+            row.emplace_back();
+            row.back().set_str(std::move(space.second));
+            rows.emplace_back();
+            rows.back().set_columns(std::move(row));
+        }
+        resp_->set_rows(std::move(rows));
+
+        DCHECK(onFinish_);
+        onFinish_();
+    };
+
+    auto error = [this] (auto &&e) {
+        LOG(ERROR) << "Exception caught: " << e.what();
+        DCHECK(onError_);
+        onError_(Status::Error("Internal error"));
+        return;
+    };
+
+    std::move(future).via(runner).thenValue(cb).thenError(error);
+}
+
 void ShowExecutor::setupResponse(cpp2::ExecutionResponse &resp) {
     resp = std::move(*resp_);
 }
diff --git a/src/executor/ShowExecutor.h b/src/executor/ShowExecutor.h
index 7c77924f3ccc32b831cf4b78c6196b0407d03cb6..7dd1bc42ad298244d428a563b021b6a699665826 100644
--- a/src/executor/ShowExecutor.h
+++ b/src/executor/ShowExecutor.h
@@ -25,6 +25,7 @@ public:
 
     void execute() override;
     void showHosts();
+    void showSpaces();
 
     void setupResponse(cpp2::ExecutionResponse &resp) override;
 
diff --git a/src/executor/test/DefineSchemaTest.cpp b/src/executor/test/DefineSchemaTest.cpp
index b362816be0885399b6fd2b972c116a337785b511..2b3b8e05b14b66b0a93e665c96cd5a5180a26660 100644
--- a/src/executor/test/DefineSchemaTest.cpp
+++ b/src/executor/test/DefineSchemaTest.cpp
@@ -146,12 +146,27 @@ TEST_F(DefineSchemaTest, metaCommunication) {
         auto code = client->execute(query, resp);
         ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code);
     }
+    {
+        cpp2::ExecutionResponse resp;
+        std::string query = "show spaces";
+        client->execute(query, resp);
+        std::vector<uniform_tuple_t<std::string, 1>> expected{
+            {"default_space"},
+        };
+        ASSERT_TRUE(verifyResult(resp, expected));
+    }
     {
         cpp2::ExecutionResponse resp;
         std::string query = "drop space default_space";
         auto code = client->execute(query, resp);
         ASSERT_EQ(cpp2::ErrorCode::SUCCEEDED, code);
     }
+    {
+        cpp2::ExecutionResponse resp;
+        std::string query = "show spaces";
+        client->execute(query, resp);
+        ASSERT_EQ(0, (*(resp.get_rows())).size());
+    }
     {
         cpp2::ExecutionResponse resp;
         std::string query = "remove hosts(\"127.0.0.1:1000\", \"127.0.0.1:1100\")";
diff --git a/src/parser/AdminSentences.cpp b/src/parser/AdminSentences.cpp
index 5a81ec9f5491b99018addbdcada5406ceab3d872..003060a6900148bb33d7428769e564b323fec75d 100644
--- a/src/parser/AdminSentences.cpp
+++ b/src/parser/AdminSentences.cpp
@@ -12,6 +12,8 @@ std::string ShowSentence::toString() const {
     switch (showType_) {
         case ShowType::kShowHosts:
             return std::string("SHOW HOSTS");
+        case ShowType::kShowSpaces:
+            return std::string("SHOW SPACES");
         case ShowType::kUnknown:
         default:
             FLOG_FATAL("Type illegal");
diff --git a/src/parser/AdminSentences.h b/src/parser/AdminSentences.h
index 989565e80c790ee41d47747d6b5ec57756c1f4cc..bb15d175a329caf17dee61d1608361e44c06f340 100644
--- a/src/parser/AdminSentences.h
+++ b/src/parser/AdminSentences.h
@@ -20,6 +20,7 @@ public:
     enum class ShowType : uint32_t {
         kUnknown,
         kShowHosts,
+        kShowSpaces
     };
 
     explicit ShowSentence(ShowType sType) {
@@ -37,6 +38,7 @@ private:
     ShowType    showType_{ShowType::kUnknown};
 };
 
+
 inline std::ostream& operator<<(std::ostream &os, ShowSentence::ShowType type) {
     return os << static_cast<uint32_t>(type);
 }
diff --git a/src/parser/parser.yy b/src/parser/parser.yy
index 4a358c05df844c06ec6629f2aeb9f3e717c1f8aa..3f5b4800c7ff6b209bc21779f3f81c87b838d255 100644
--- a/src/parser/parser.yy
+++ b/src/parser/parser.yy
@@ -74,7 +74,7 @@ class GraphScanner;
 %token KW_EDGE KW_UPDATE KW_STEPS KW_OVER KW_UPTO KW_REVERSELY KW_SPACE KW_DELETE KW_FIND
 %token KW_INT KW_BIGINT KW_DOUBLE KW_STRING KW_BOOL KW_TAG KW_UNION KW_INTERSECT KW_MINUS
 %token KW_NO KW_OVERWRITE KW_IN KW_DESCRIBE KW_SHOW KW_HOSTS KW_TIMESTAMP KW_ADD KW_CREATE
-%token KW_PARTITION_NUM KW_REPLICA_FACTOR KW_DROP KW_REMOVE
+%token KW_PARTITION_NUM KW_REPLICA_FACTOR KW_DROP KW_REMOVE KW_SPACES
 /* symbols */
 %token L_PAREN R_PAREN L_BRACKET R_BRACKET L_BRACE R_BRACE COMMA
 %token PIPE OR AND LT LE GT GE EQ NE ADD SUB MUL DIV MOD NOT NEG ASSIGN
@@ -765,6 +765,9 @@ show_sentence
     : KW_SHOW KW_HOSTS {
         $$ = new ShowSentence(ShowSentence::ShowType::kShowHosts);
     }
+    | KW_SHOW KW_SPACES {
+        $$ = new ShowSentence(ShowSentence::ShowType::kShowSpaces);
+    }
     ;
 
 add_hosts_sentence
diff --git a/src/parser/scanner.lex b/src/parser/scanner.lex
index 0c658adb296546f405e5e16281e4bc109ae381f9..cfe8fcecafbf2cb15a3e7ec230511a210b193823 100644
--- a/src/parser/scanner.lex
+++ b/src/parser/scanner.lex
@@ -46,6 +46,7 @@ OVER                        ([Oo][Vv][Ee][Rr])
 UPTO                        ([Uu][Pp][Tt][Oo])
 REVERSELY                   ([Rr][Ee][Vv][Ee][Rr][Ss][Ee][Ll][Yy])
 SPACE                       ([Ss][Pp][Aa][Cc][Ee])
+SPACES                      ([Ss][Pp][Aa][Cc][Ee][Ss])
 TTL                         ([Tt][Tt][Ll])
 INT                         ([Ii][Nn][Tt])
 BIGINT                      ([Bb][Ii][Gg][Ii][Nn][Tt])
@@ -107,6 +108,7 @@ OCT                         ([0-7])
 {UPTO}                      { return TokenType::KW_UPTO; }
 {REVERSELY}                 { return TokenType::KW_REVERSELY; }
 {SPACE}                     { return TokenType::KW_SPACE; }
+{SPACES}                    { return TokenType::KW_SPACES; }
 {TTL}                       { return TokenType::KW_TTL; }
 {INT}                       { return TokenType::KW_INT; }
 {BIGINT}                    { return TokenType::KW_BIGINT; }
diff --git a/src/parser/test/ParserTest.cpp b/src/parser/test/ParserTest.cpp
index 13123e0839190a4cbc4bbc59b49ace6a6299a968..3fd19fa069466322b6463db899627bda0f55eca7 100644
--- a/src/parser/test/ParserTest.cpp
+++ b/src/parser/test/ParserTest.cpp
@@ -388,6 +388,12 @@ TEST(Parser, AdminOperation) {
         auto result = parser.parse(query);
         ASSERT_TRUE(result.ok()) << result.status();
     }
+    {
+        GQLParser parser;
+        std::string query = "show spaces";
+        auto result = parser.parse(query);
+        ASSERT_TRUE(result.ok()) << result.status();
+    }
     {
         GQLParser parser;
         std::string query = "drop space default_space";
diff --git a/src/parser/test/ScannerTest.cpp b/src/parser/test/ScannerTest.cpp
index 6684abeb69df98e48a4a5fbf98480117994720c2..ea1e92038be84f17ac6e64ebcba51360ddbffbf4 100644
--- a/src/parser/test/ScannerTest.cpp
+++ b/src/parser/test/ScannerTest.cpp
@@ -186,6 +186,8 @@ TEST(Scanner, Basic) {
         CHECK_SEMANTIC_TYPE("reversely", TokenType::KW_REVERSELY),
         CHECK_SEMANTIC_TYPE("SPACE", TokenType::KW_SPACE),
         CHECK_SEMANTIC_TYPE("space", TokenType::KW_SPACE),
+        CHECK_SEMANTIC_TYPE("SPACES", TokenType::KW_SPACES),
+        CHECK_SEMANTIC_TYPE("spaces", TokenType::KW_SPACES),
         CHECK_SEMANTIC_TYPE("TTL", TokenType::KW_TTL),
         CHECK_SEMANTIC_TYPE("ttl", TokenType::KW_TTL),
         CHECK_SEMANTIC_TYPE("BIGINT", TokenType::KW_BIGINT),