diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index fb1429ec..95e1e4d9 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -19,6 +19,8 @@ jobs:
       run: sudo apt update -y
     - name: Install libev
       run: sudo apt install -y libev4 libev-dev
+    - name: Install cJSON
+      run: sudo apt install -y libcjson1 libcjson-dev
     - name: Install systemd
       run: sudo apt install -y libsystemd-dev
     - name: Install rst2man
@@ -63,6 +65,8 @@ jobs:
       run: brew install openssl
     - name: Install libev
       run: brew install libev
+    - name: Install cJSON
+      run: brew install cjson
     - name: Install rst2man
       run: brew install docutils
     - name: Install clang
@@ -71,7 +75,7 @@ jobs:
       run: mkdir build
       working-directory: /Users/runner/work/pgagroal/pgagroal/
     - name: GCC/cmake
-      run: export CC=/usr/bin/gcc && export OPENSSL_ROOT_DIR=`brew --prefix openssl` && cmake -DCMAKE_BUILD_TYPE=Debug ..
+      run: export CC=/usr/bin/gcc && export OPENSSL_ROOT_DIR=`brew --prefix openssl` && cmake -DCMAKE_BUILD_TYPE=Debug  ..
       working-directory: /Users/runner/work/pgagroal/pgagroal/build/
     - name: GCC/make
       run: make
@@ -83,7 +87,7 @@ jobs:
       run: mkdir build
       working-directory: /Users/runner/work/pgagroal/pgagroal/
     - name: CLANG/cmake
-      run: export CC=/usr/bin/clang && export OPENSSL_ROOT_DIR=`brew --prefix openssl` && cmake -DCMAKE_BUILD_TYPE=Debug ..
+      run: export CC=/usr/bin/clang && export OPENSSL_ROOT_DIR=`brew --prefix openssl` && cmake -DCMAKE_BUILD_TYPE=Debug  ..
       working-directory: /Users/runner/work/pgagroal/pgagroal/build/
     - name: CLANG/make
       run: make
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 94c34ae8..a60633b4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -78,6 +78,16 @@ else ()
   message(FATAL_ERROR "rst2man needed")
 endif()
 
+# search for cJSON library
+# <https://github.com/DaveGamble/cJSON>
+find_package(cJSON)
+if (cJSON_FOUND)
+  message(STATUS "cJSON found version ${CJSON_VERSION}")
+else ()
+  message(FATAL_ERROR "cJSON needed")
+endif()
+
+
 if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
   find_package(Libatomic)
   if (LIBATOMIC_FOUND)
diff --git a/README.md b/README.md
index 7298f721..070703a4 100644
--- a/README.md
+++ b/README.md
@@ -69,6 +69,7 @@ See [Architecture](./doc/ARCHITECTURE.md) for the architecture of `pgagroal`.
 * [systemd](https://www.freedesktop.org/wiki/Software/systemd/)
 * [rst2man](https://docutils.sourceforge.io/)
 * [libatomic](https://gcc.gnu.org/wiki/Atomic)
+* [cJSON](https://github.com/DaveGamble/cJSON)
 
 On Rocky Linux (and similar) operating systems, the dependencies
 can be installed via `dnf(8)` as follows:
@@ -79,7 +80,8 @@ dnf install git gcc cmake make    \
             openssl openssl-devel \
 	    systemd systemd-devel \
 	    python3-docutils      \
-	    libatomic
+	    libatomic             \
+	    cjson cjson-devel
 ```
 
 Please note that, on Rocky Linux, in order to install the `python3-docutils`
diff --git a/cmake/FindcJSON.cmake b/cmake/FindcJSON.cmake
new file mode 100644
index 00000000..6f30e309
--- /dev/null
+++ b/cmake/FindcJSON.cmake
@@ -0,0 +1,51 @@
+# FindcJSON.cmake
+# Tries to find cJSON libraries on the system
+# (e.g., on Rocky Linux: cjson and cjson-devel)
+#
+# Inspired by <https://sources.debian.org/src/monado/21.0.0~dfsg1-1/cmake/FindcJSON.cmake/>
+#
+# If cJSON is found, sets the following variables:
+# - CJSON_INCLUDE_DIRS
+# - CJSON_LIBRARIES
+# - CJSON_VERSION
+#
+# In the header file cJSON.h the library version is specified as:
+# #define CJSON_VERSION_MAJOR 1
+# #define CJSON_VERSION_MINOR 7
+# #define CJSON_VERSION_PATCH 14
+
+
+find_path(
+    CJSON_INCLUDE_DIR
+    NAMES cjson/cJSON.h
+    PATH_SUFFIXES include)
+find_library(
+    CJSON_LIBRARY
+    NAMES cjson
+    PATH_SUFFIXES lib)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(cJSON REQUIRED_VARS CJSON_INCLUDE_DIR
+                                                      CJSON_LIBRARY)
+if(CJSON_FOUND)
+  # these variables are needed for the build
+  set( CJSON_INCLUDE_DIRS "${CJSON_INCLUDE_DIR}" )
+  set( CJSON_LIBRARIES    "${CJSON_LIBRARY}"     )
+
+  # try to get out the library version from the headers
+  file(STRINGS "${CJSON_INCLUDE_DIR}/cjson/cJSON.h"
+    CJSON_VERSION_MAJOR REGEX "^#define[ \t]+CJSON_VERSION_MAJOR[ \t]+[0-9]+")
+  file(STRINGS "${CJSON_INCLUDE_DIR}/cjson/cJSON.h"
+    CJSON_VERSION_MINOR REGEX "^#define[ \t]+CJSON_VERSION_MINOR[ \t]+[0-9]+")
+    file(STRINGS "${CJSON_INCLUDE_DIR}/cjson/cJSON.h"
+    CJSON_VERSION_PATCH REGEX "^#define[ \t]+CJSON_VERSION_PATCH[ \t]+[0-9]+")
+  string(REGEX REPLACE "[^0-9]+" "" CJSON_VERSION_MAJOR "${CJSON_VERSION_MAJOR}")
+  string(REGEX REPLACE "[^0-9]+" "" CJSON_VERSION_MINOR "${CJSON_VERSION_MINOR}")
+  string(REGEX REPLACE "[^0-9]+" "" CJSON_VERSION_PATCH "${CJSON_VERSION_PATCH}")
+  set(CJSON_VERSION "${CJSON_VERSION_MAJOR}.${CJSON_VERSION_MINOR}.${CJSON_VERSION_PATCH}")
+  unset(CJSON_VERSION_MINOR)
+  unset(CJSON_VERSION_MAJOR)
+  unset(CJSON_VERSION_PATCH)
+endif()
+
+mark_as_advanced( CJSON_INCLUDE_DIR CJSON_LIBRARY )  
diff --git a/doc/CLI.md b/doc/CLI.md
index 3a3d5a6a..5bf6056f 100644
--- a/doc/CLI.md
+++ b/doc/CLI.md
@@ -22,6 +22,7 @@ Available options are the following ones:
 -U, --user USERNAME      Set the user name
 -P, --password PASSWORD  Set the password
 -L, --logfile FILE       Set the log file
+-F, --format  text|json  Set the output format
 -v, --verbose            Output text string of result
 -V, --version            Display version information
 -?, --help               Display help
@@ -30,6 +31,11 @@ Available options are the following ones:
 
 Options can be specified either in short or long form, in any position of the command line.
 
+By default the command output, if any, is reported as text. It is possible to specify JSON as the output format,
+and this is the suggested format if there is the need to automtically parse the command output, since the text format
+could be subject to changes in future releases. For more information about the JSON output format,
+please see the [JSON Output Format](#json-output-format) section.
+
 ## Commands
 
 ### flush
@@ -380,3 +386,203 @@ pgagroal-cli reset-server 2>/dev/null
 
 There is a minimal shell completion support for `pgagroal-cli`.
 Please refer to the [Install pgagroal](https://github.com/agroal/pgagroal/blob/master/doc/tutorial/01_install.md) tutorial for detailed information about how to enable and use shell completions.
+
+
+## JSON Output Format
+
+It is possible to obtain the output of a command in a JSON format by specyfing the `-F` (`--format`) option on the command line.
+Supported output formats are:
+- `text` (the default)
+- `json`
+
+As an example, the following are invocations of commands with different output formats:
+
+```
+pgagroal-cli status     # defaults to text output format
+
+pgagroal-cli status --format text  # same as above
+pgagroal-cli status -F text        # same as above
+
+pgagroal-cli status --format json  # outputs as JSON text
+pgagroal-cli status -F json        # same as above
+```
+
+Whenever a command produces output, the latter can be obtained in a JSON format.
+Every command output consists of an object that contains two other objects:
+- a `command` object, with all the details about the command and its output;
+- an `application` object, with all the details about the executable that launched the command (e.g., `pgagroal-cli`).
+
+In the following, details about every object are provided:
+
+### The `application` object
+
+The `application` object is made by the following attributes:
+- `name` a string representing the name of the executable that launched the command;
+- `version` a string representing the version of the executable;
+- `major`, `minor`, `patch` are integers representing every single part of the version of the application.
+
+As an example, when `pgagroal-cli` launches a command, the output includes an `application` object like the following:
+
+```
+ "application":  {
+                "name": "pgagroal-cli",
+                "major":        1,
+                "minor":        6,
+                "patch":        0,
+                "version":      "1.6.0"
+        }
+```
+
+
+### The `command` object
+
+The `command` object represents the launched command and contains also the answer from the `pgagroal`.
+The object is made by the following attributes:
+- `name` a string representing the command launched (e.g., `status`);
+- `status` a string that contains either "OK" or an error string if the command failed;
+- `error` an interger value used as a flag to indicate if the command was in error or not, where `0` means success and `1` means error;
+- `exit-status` an integer that contains zero if the command run succesfully, another value depending on the specific command in case of failure;
+- `output` an object that contains the details of the executed command.
+
+The `output` object is *the variable part* in the JSON command output, that means its effective content depends on the launched command.
+
+Whenever the command output includes an array of stuff, for example a connection list, such array is wrapped into a `list` JSON array with a sibling named `count` that contains the integer size of the array (number of elements).
+
+
+The following are a few examples of commands that provide output in JSON:
+
+
+```
+pgagroal-cli ping --format json
+{
+        "command":      {
+                "name": "ping",
+                "status":       "OK",
+                "error":        0,
+                "exit-status":  0,
+                "output":       {
+                        "status":       1,
+                        "message":      "running"
+                }
+        },
+        "application":  {
+                "name": "pgagroal-cli",
+                "major":        1,
+                "minor":        6,
+                "patch":        0,
+                "version":      "1.6.0"
+        }
+}
+
+
+
+pgagroal-cli status --format json
+{
+        "command":      {
+                "name": "status",
+                "status":       "OK",
+                "error":        0,
+                "exit-status":  0,
+                "output":       {
+                        "status":       {
+                                "message":      "Running",
+                                "status":       1
+                        },
+                        "connections":  {
+                                "active":       0,
+                                "total":        2,
+                                "max":  15
+                        },
+                        "databases":    {
+                                "disabled":     {
+                                        "count":        0,
+                                        "state":        "disabled",
+                                        "list": []
+                                }
+                        }
+                }
+        },
+        "application":  {
+                "name": "pgagroal-cli",
+                "major":        1,
+                "minor":        6,
+                "patch":        0,
+                "version":      "1.6.0"
+        }
+}
+```
+
+As an example, the following is the output of a faulty `conf set` command (note the `status`, `error` and `exist-status` values):
+
+```
+pgagroal-cli conf set max_connections 1000  --format json
+{
+        "command":      {
+                "name": "conf set",
+                "status":       "Current and expected values are different",
+                "error":        true,
+                "exit-status":  2,
+                "output":       {
+                        "key":  "max_connections",
+                        "value":        "15",
+                        "expected":     "1000"
+                }
+        },
+        "application":  {
+                "name": "pgagroal-cli",
+                "major":        1,
+                "minor":        6,
+                "patch":        0,
+                "version":      "1.6.0"
+        }
+}
+```
+
+
+The `conf ls` command returns an array named `files` where each entry is made by a couple `description` and `path`, where the former
+is the mnemonic name of the configuration file, and the latter is the value of the configuration file used:
+
+```
+$ pgagroal-cli conf ls --format json
+{
+        "command":      {
+                "name": "conf ls",
+                "status":       "OK",
+                "error":        0,
+                "exit-status":  0,
+                "output":       {
+                        "files":        {
+                                "list": [{
+                                                "description":  "Main Configuration file",
+                                                "path": "/etc/pgagroal/pgagroal.conf"
+                                        }, {
+                                                "description":  "HBA File",
+                                                "path": "/etc/pgagroal/pgagroal_hba.conf"
+                                        }, {
+                                                "description":  "Limit file",
+                                                "path": "/etc/pgagroal/pgagroal_databases.conf"
+                                        }, {
+                                                "description":  "Frontend users file",
+                                                "path": "/etc/pgagroal/pgagroal_frontend_users.conf"
+                                        }, {
+                                                "description":  "Admins file",
+                                                "path": "/etc/pgagroal/pgagroal_admins.conf"
+                                        }, {
+                                                "description":  "Superuser file",
+                                                "path": ""
+                                        }, {
+                                                "description":  "Users file",
+                                                "path": "/etc/pgagroal/pgagroal_users.conf"
+                                        }]
+                        }
+                }
+        },
+        "application":  {
+                "name": "pgagroal-cli",
+                "major":        1,
+                "minor":        6,
+                "patch":        0,
+                "version":      "1.6.0"
+        }
+}
+```
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 51ce9027..fea97ab9 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -22,6 +22,7 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
     ${LIBEV_INCLUDE_DIRS}
     ${OPENSSL_INCLUDE_DIR}
     ${SYSTEMD_INCLUDE_DIRS}
+    ${CJSON_INCLUDE_DIRS}
   )
 
   #
@@ -33,6 +34,7 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
     ${OPENSSL_SSL_LIBRARY}
     ${SYSTEMD_LIBRARIES}
     ${LIBATOMIC_LIBRARY}
+    ${CJSON_LIBRARIES}
   )
 
   set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined")
@@ -69,6 +71,7 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
     ${CMAKE_CURRENT_SOURCE_DIR}/include
     ${LIBEV_INCLUDE_DIRS}
     ${OPENSSL_INCLUDE_DIRS}
+    ${CJSON_INCLUDE_DIRS}
   )
 
   #
@@ -77,6 +80,7 @@ elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
   link_libraries(
     ${LIBEV_LIBRARIES}
     ${OPENSSL_LIBRARIES}
+    ${CJSON_LIBRARIES}
   )
 else()
 
@@ -98,6 +102,7 @@ else()
     ${CMAKE_CURRENT_SOURCE_DIR}/include
     ${LIBEV_INCLUDE_DIRS}
     ${OPENSSL_INCLUDE_DIRS}
+    ${CJSON_INCLUDE_DIRS}
   )
 
   #
@@ -106,6 +111,7 @@ else()
   link_libraries(
     ${LIBEV_LIBRARIES}
     ${OPENSSL_LIBRARIES}
+    ${CJSON_LIBRARIES}
   )
 endif()
 
@@ -314,3 +320,4 @@ endif()
 target_link_libraries(pgagroal-admin-bin pgagroal)
 
 install(TARGETS pgagroal-admin-bin DESTINATION ${CMAKE_INSTALL_BINDIR})
+
diff --git a/src/cli.c b/src/cli.c
index d59fd0ec..0ce08efc 100644
--- a/src/cli.c
+++ b/src/cli.c
@@ -74,16 +74,16 @@ static int disabledb(SSL* ssl, int socket, char* database);
 static int gracefully(SSL* ssl, int socket);
 static int stop(SSL* ssl, int socket);
 static int cancel_shutdown(SSL* ssl, int socket);
-static int status(SSL* ssl, int socket);
-static int details(SSL* ssl, int socket);
-static int isalive(SSL* ssl, int socket);
+static int status(SSL* ssl, int socket, char output_format);
+static int details(SSL* ssl, int socket, char output_format);
+static int isalive(SSL* ssl, int socket, char output_format);
 static int reset(SSL* ssl, int socket);
 static int reset_server(SSL* ssl, int socket, char* server);
 static int switch_to(SSL* ssl, int socket, char* server);
 static int reload(SSL* ssl, int socket);
-static int config_get(SSL* ssl, int socket, char* config_key, bool verbose);
-static int config_set(SSL* ssl, int socket, char* config_key, char* config_value, bool verbose);
-static int config_ls(SSL* ssl, int socket);
+static int config_ls(SSL* ssl, int socket, char output_format);
+static int config_get(SSL* ssl, int socket, char* config_key, bool verbose, char output_format);
+static int config_set(SSL* ssl, int socket, char* config_key, char* config_value, bool verbose, char output_format);
 
 static void
 version(void)
@@ -110,6 +110,7 @@ usage(void)
    printf("  -U, --user USERNAME      Set the user name\n");
    printf("  -P, --password PASSWORD  Set the password\n");
    printf("  -L, --logfile FILE       Set the log file\n");
+   printf("  -F, --format text|json   Set the output format\n");
    printf("  -v, --verbose            Output text string of result\n");
    printf("  -V, --version            Display version information\n");
    printf("  -?, --help               Display help\n");
@@ -176,6 +177,7 @@ main(int argc, char** argv)
    long l_port;
    char* config_key = NULL; /* key for a configuration setting */
    char* config_value = NULL; /* value for a configuration setting */
+   char output_format = COMMAND_OUTPUT_FORMAT_TEXT;
 
    while (1)
    {
@@ -187,12 +189,13 @@ main(int argc, char** argv)
          {"user", required_argument, 0, 'U'},
          {"password", required_argument, 0, 'P'},
          {"logfile", required_argument, 0, 'L'},
+         {"format", required_argument, 0, 'F' },
          {"verbose", no_argument, 0, 'v'},
          {"version", no_argument, 0, 'V'},
          {"help", no_argument, 0, '?'}
       };
 
-      c = getopt_long(argc, argv, "vV?c:h:p:U:P:L:",
+      c = getopt_long(argc, argv, "vV?c:h:p:U:P:L:F:",
                       long_options, &option_index);
 
       if (c == -1)
@@ -220,6 +223,16 @@ main(int argc, char** argv)
          case 'L':
             logfile = optarg;
             break;
+         case 'F':
+            if (!strncmp(optarg, "json", MISC_LENGTH))
+            {
+               output_format = COMMAND_OUTPUT_FORMAT_JSON;
+            }
+            else
+            {
+               output_format = COMMAND_OUTPUT_FORMAT_TEXT;
+            }
+            break;
          case 'v':
             verbose = true;
             break;
@@ -580,15 +593,15 @@ main(int argc, char** argv)
    }
    else if (action == ACTION_STATUS)
    {
-      exit_code = status(s_ssl, socket);
+      exit_code = status(s_ssl, socket, output_format);
    }
    else if (action == ACTION_STATUS_DETAILS)
    {
-      exit_code = details(s_ssl, socket);
+      exit_code = details(s_ssl, socket, output_format);
    }
    else if (action == ACTION_ISALIVE)
    {
-      exit_code = isalive(s_ssl, socket);
+      exit_code = isalive(s_ssl, socket, output_format);
    }
    else if (action == ACTION_RESET)
    {
@@ -608,15 +621,15 @@ main(int argc, char** argv)
    }
    else if (action == ACTION_CONFIG_GET)
    {
-      exit_code = config_get(s_ssl, socket, config_key, verbose);
+      exit_code = config_get(s_ssl, socket, config_key, verbose, output_format);
    }
    else if (action == ACTION_CONFIG_SET)
    {
-      exit_code = config_set(s_ssl, socket, config_key, config_value, verbose);
+      exit_code = config_set(s_ssl, socket, config_key, config_value, verbose, output_format);
    }
    else if (action == ACTION_CONFIG_LS)
    {
-      exit_code = config_ls(s_ssl, socket);
+      exit_code = config_ls(s_ssl, socket, output_format);
    }
 
 done:
@@ -743,11 +756,11 @@ cancel_shutdown(SSL* ssl, int socket)
 }
 
 static int
-status(SSL* ssl, int socket)
+status(SSL* ssl, int socket, char output_format)
 {
    if (pgagroal_management_status(ssl, socket) == 0)
    {
-      return pgagroal_management_read_status(ssl, socket);
+      return pgagroal_management_read_status(ssl, socket, output_format);
    }
    else
    {
@@ -756,14 +769,12 @@ status(SSL* ssl, int socket)
 }
 
 static int
-details(SSL* ssl, int socket)
+details(SSL* ssl, int socket, char output_format)
 {
    if (pgagroal_management_details(ssl, socket) == 0)
    {
-      if (pgagroal_management_read_status(ssl, socket) == 0)
-      {
-         return pgagroal_management_read_details(ssl, socket);
-      }
+      return pgagroal_management_read_details(ssl, socket, output_format);
+
    }
 
    // if here, an error occurred
@@ -772,18 +783,18 @@ details(SSL* ssl, int socket)
 }
 
 static int
-isalive(SSL* ssl, int socket)
+isalive(SSL* ssl, int socket, char output_format)
 {
    int status = -1;
 
    if (pgagroal_management_isalive(ssl, socket) == 0)
    {
-      if (pgagroal_management_read_isalive(ssl, socket, &status))
+      if (pgagroal_management_read_isalive(ssl, socket, &status, output_format))
       {
          return EXIT_STATUS_CONNECTION_ERROR;
       }
 
-      if (status != 1 && status != 2)
+      if (status != PING_STATUS_RUNNING && status != PING_STATUS_SHUTDOWN_GRACEFULLY)
       {
          return EXIT_STATUS_CONNECTION_ERROR;
       }
@@ -851,12 +862,12 @@ reload(SSL* ssl, int socket)
  * @param config_key the key of the configuration parameter, that is the name
  * of the configuration parameter to read.
  * @param verbose if true the function will print on STDOUT also the config key
+ * @param output_format the format for the output (e.g., json)
  * @returns 0 on success, 1 on network failure, 2 on data failure
  */
 static int
-config_get(SSL* ssl, int socket, char* config_key, bool verbose)
+config_get(SSL* ssl, int socket, char* config_key, bool verbose, char output_format)
 {
-   char* buffer = NULL;
 
    if (!config_key || strlen(config_key) > MISC_LENGTH)
    {
@@ -867,40 +878,10 @@ config_get(SSL* ssl, int socket, char* config_key, bool verbose)
    {
       goto error;
    }
-   else
-   {
-      buffer = calloc(1, MISC_LENGTH);
-      if (buffer == NULL)
-      {
-         goto error;
-      }
-      if (pgagroal_management_read_config_get(socket, &buffer))
-      {
-         free(buffer);
-         goto error;
-      }
 
-      // an empty response means that the
-      // requested configuration parameter has not been
-      // found, so throw an error
-      if (buffer && strlen(buffer))
-      {
-         if (verbose)
-         {
-            printf("%s = %s\n", config_key, buffer);
-         }
-         else
-         {
-            printf("%s\n", buffer);
-         }
-      }
-      else
-      {
-         free(buffer);
-         return EXIT_STATUS_DATA_ERROR;
-      }
-
-      free(buffer);
+   if (pgagroal_management_read_config_get(socket, config_key, NULL, verbose, output_format))
+   {
+      goto error;
    }
 
    return EXIT_STATUS_OK;
@@ -923,10 +904,10 @@ config_get(SSL* ssl, int socket, char* config_key, bool verbose)
  * @return 0 on success
  */
 static int
-config_set(SSL* ssl, int socket, char* config_key, char* config_value, bool verbose)
+config_set(SSL* ssl, int socket, char* config_key, char* config_value, bool verbose, char output_format)
 {
-   char* buffer = NULL;
-   int status = EXIT_STATUS_DATA_ERROR;
+
+   int status = EXIT_STATUS_OK;
 
    if (!config_key || strlen(config_key) > MISC_LENGTH
        || !config_value || strlen(config_value) > MISC_LENGTH)
@@ -938,45 +919,8 @@ config_set(SSL* ssl, int socket, char* config_key, char* config_value, bool verb
    {
       goto error;
    }
-   else
-   {
-      buffer = malloc(MISC_LENGTH);
-      memset(buffer, 0, MISC_LENGTH);
-      if (pgagroal_management_read_config_get(socket, &buffer))
-      {
-         free(buffer);
-         goto error;
-      }
 
-      // if the setting we sent is different from the setting we get
-      // than the system has not applied, so it is an error
-      if (strncmp(config_value, buffer, MISC_LENGTH) == 0)
-      {
-         status = EXIT_STATUS_OK;
-      }
-      else
-      {
-         status = EXIT_STATUS_DATA_ERROR;
-      }
-
-      // assume an empty response is ok,
-      // do not throw an error to indicate no configuration
-      // setting with such name as been found
-      if (buffer && strlen(buffer))
-      {
-         if (verbose)
-         {
-            printf("%s = %s\n", config_key, buffer);
-         }
-         else
-         {
-            printf("%s\n", buffer);
-         }
-      }
-
-      free(buffer);
-      return status;
-   }
+   status = pgagroal_management_read_config_get(socket, config_key, config_value, verbose, output_format);
 
    return status;
 error:
@@ -989,7 +933,7 @@ config_set(SSL* ssl, int socket, char* config_key, char* config_value, bool verb
  * @returns 0 on success
  */
 static int
-config_ls(SSL* ssl, int socket)
+config_ls(SSL* ssl, int socket, char output_format)
 {
 
    if (pgagroal_management_conf_ls(ssl, socket))
@@ -997,7 +941,7 @@ config_ls(SSL* ssl, int socket)
       goto error;
    }
 
-   if (pgagroal_management_read_conf_ls(ssl, socket))
+   if (pgagroal_management_read_conf_ls(ssl, socket, output_format))
    {
       goto error;
    }
diff --git a/src/include/json.h b/src/include/json.h
new file mode 100644
index 00000000..7087aab1
--- /dev/null
+++ b/src/include/json.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2023 Red Hat
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* pgagroal */
+#include <pgagroal.h>
+
+#include <cjson/cJSON.h>
+
+/**
+ * JSON related command tags, used to build and retrieve
+ * a JSON piece of information related to a single command
+ */
+#define JSON_TAG_COMMAND "command"
+#define JSON_TAG_COMMAND_NAME "name"
+#define JSON_TAG_COMMAND_STATUS "status"
+#define JSON_TAG_COMMAND_ERROR "error"
+#define JSON_TAG_COMMAND_OUTPUT "output"
+#define JSON_TAG_COMMAND_EXIT_STATUS "exit-status"
+
+#define JSON_TAG_APPLICATION_NAME "name"
+#define JSON_TAG_APPLICATION_VERSION_MAJOR "major"
+#define JSON_TAG_APPLICATION_VERSION_MINOR "minor"
+#define JSON_TAG_APPLICATION_VERSION_PATCH "patch"
+#define JSON_TAG_APPLICATION_VERSION "version"
+
+#define JSON_TAG_ARRAY_NAME "list"
+
+/**
+ * JSON pre-defined values
+ */
+#define JSON_STRING_SUCCESS "OK"
+#define JSON_STRING_ERROR   "KO"
+#define JSON_BOOL_SUCCESS   0
+#define JSON_BOOL_ERROR     1
+
+/**
+ * Utility method to create a new JSON object that wraps a
+ * single command. This method should be called to initialize the
+ * object and then the other specific methods that read the
+ * answer from pgagroal should populate the object accordingly.
+ *
+ * Moreover, an 'application' object is placed to indicate from
+ * where the command has been launched (i.e., which executable)
+ * and at which version.
+ *
+ * @param command_name the name of the command this object wraps
+ * an answer for
+ * @param success true if the command is supposed to be succesfull
+ * @returns the new JSON object to use and populate
+ * @param executable_name the name of the executable that is creating this
+ * response object
+ */
+cJSON* json_create_new_command_object(char* command_name, bool success, char* executable_name);
+
+/**
+ * Utility method to "jump" to the output JSON object wrapped into
+ * a command object.
+ *
+ * The "output" object is the one that every single method that reads
+ * back an answer from pgagroal has to populate in a specific
+ * way according to the data received from pgagroal.
+ *
+ * @param json the command object that wraps the command
+ * @returns the pointer to the output object of NULL in case of an error
+ */
+cJSON* json_extract_command_output_object(cJSON* json);
+
+/**
+ * Utility function to set a command JSON object as faulty, that
+ * means setting the 'error' and 'status' message accordingly.
+ *
+ * @param json the whole json object that must include the 'command'
+ * tag
+ * @param message the message to use to set the faulty diagnostic
+ * indication
+ *
+ * @param exit status
+ *
+ * @returns 0 on success
+ *
+ * Example:
+ * json_set_command_object_faulty( json, strerror( errno ) );
+ */
+int json_set_command_object_faulty(cJSON* json, char* message, int exit_status);
+
+/**
+ * Utility method to inspect if a JSON object that wraps a command
+ * is faulty, that means if it has the error flag set to true.
+ *
+ * @param json the json object to analyzer
+ * @returns the value of the error flag in the object, or false if
+ * the object is not valid
+ */
+bool json_is_command_object_faulty(cJSON* json);
+
+/**
+ * Utility method to extract the message related to the status
+ * of the command wrapped in the JSON object.
+ *
+ * @param json the JSON object to analyze
+ * #returns the status message or NULL in case the JSON object is not valid
+ */
+const char* json_get_command_object_status(cJSON* json);
+
+/**
+ * Utility method to check if a JSON object wraps a specific command name.
+ *
+ * @param json the JSON object to analyze
+ * @param command_name the name to search for
+ * @returns true if the command name matches, false otherwise and in case
+ * the JSON object is not valid or the command name is not valid
+ */
+bool json_is_command_name_equals_to(cJSON* json, char* command_name);
+
+/**
+ * Utility method to print out the JSON object
+ * on standard output.
+ *
+ * After the object has been printed, it is destroyed, so
+ * calling this method will make the pointer invalid
+ * and the jeon object cannot be used anymore.
+ *
+ * This should be the last method to be called
+ * when there is the need to print out the information
+ * contained in a json object.
+ *
+ * @param json the json object to print
+ */
+void json_print_and_free_json_object(cJSON* json);
+
+/**
+ * Utility function to get the exit status of a given command wrapped in a JSON object.
+ *
+ * @param json the json object
+ * @returns the exit status of the command
+ */
+int json_command_object_exit_status(cJSON* json);
diff --git a/src/include/management.h b/src/include/management.h
index cd640027..167473e4 100644
--- a/src/include/management.h
+++ b/src/include/management.h
@@ -63,6 +63,18 @@ extern "C" {
 #define MANAGEMENT_CONFIG_SET         21
 #define MANAGEMENT_CONFIG_LS          22
 
+/**
+ * Status for the 'ping' (i.e., is-alive) command
+ */
+#define PING_STATUS_RUNNING 1
+#define PING_STATUS_SHUTDOWN_GRACEFULLY 2
+
+/**
+ * Available command output formats
+ */
+#define COMMAND_OUTPUT_FORMAT_TEXT 'T'
+#define COMMAND_OUTPUT_FORMAT_JSON 'J'
+
 /**
  * Read the management header
  * @param socket The socket descriptor
@@ -179,10 +191,11 @@ pgagroal_management_status(SSL* ssl, int socket);
 /**
  * Management: Read status
  * @param socket The socket
+ * @param output_format a char describing the type of output (text or json)
  * @return 0 upon success, otherwise 1
  */
 int
-pgagroal_management_read_status(SSL* ssl, int socket);
+pgagroal_management_read_status(SSL* ssl, int socket, char output_format);
 
 /**
  * Management: Write status
@@ -205,10 +218,11 @@ pgagroal_management_details(SSL* ssl, int socket);
 /**
  * Management: Read details
  * @param socket The socket
+ * @param output_format the output format for this command (text, json)
  * @return 0 upon success, otherwise 1
  */
 int
-pgagroal_management_read_details(SSL* ssl, int socket);
+pgagroal_management_read_details(SSL* ssl, int socket, char output_format);
 
 /**
  * Management: Write details
@@ -233,7 +247,7 @@ pgagroal_management_isalive(SSL* ssl, int socket);
  * @return 0 upon success, otherwise 1
  */
 int
-pgagroal_management_read_isalive(SSL* ssl, int socket, int* status);
+pgagroal_management_read_isalive(SSL* ssl, int socket, int* status, char output_format);
 
 /**
  * Management: Write isalive
@@ -332,10 +346,14 @@ pgagroal_management_config_get(SSL* ssl, int socket, char* config_key);
  * @see pgagroal_management_read_payload
  *
  * @param ssl the socket file descriptor
+ * @param config_key the key to read (is used only to print in the output)
+ * @param verbose verbosity flag
+ * @param output_format the output format
+ * @param expected_value if set, a value that the configuration should match
  * @return 0 on success
  */
 int
-pgagroal_management_read_config_get(int socket, char** data);
+pgagroal_management_read_config_get(int socket, char* config_key, char* expected_value, bool verbose, char output_format);
 
 /**
  * Management operation: write the result of a config_get action on the socket.
@@ -414,10 +432,11 @@ pgagroal_management_conf_ls(SSL* ssl, int fd);
  *
  * @param socket the file descriptor of the open socket
  * @param ssl the SSL handler
+ * @param output_format the format to output the command result
  * @returns 0 on success
  */
 int
-pgagroal_management_read_conf_ls(SSL* ssl, int socket);
+pgagroal_management_read_conf_ls(SSL* ssl, int socket, char output_format);
 
 /**
  * The management function responsible for sending
diff --git a/src/include/utils.h b/src/include/utils.h
index f9fd7db5..adbdd7f9 100644
--- a/src/include/utils.h
+++ b/src/include/utils.h
@@ -494,6 +494,20 @@ parse_deprecated_command(int argc,
                          char* deprecated_by,
                          unsigned int deprecated_since_major,
                          unsigned int deprecated_since_minor);
+
+/**
+ * Given a server state, it returns a string that
+ * described the state in a human-readable form.
+ *
+ * If the state cannot be determined, the numeric
+ * form of the state is returned as a string.
+ *
+ * @param state the value of the sate for the server
+ * @returns the string representing the state
+ */
+char*
+pgagroal_server_state_as_string(signed char state);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/libpgagroal/json.c b/src/libpgagroal/json.c
new file mode 100644
index 00000000..53d97399
--- /dev/null
+++ b/src/libpgagroal/json.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2023 Red Hat
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list
+ * of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this
+ * list of conditions and the following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* pgagroal */
+#include <pgagroal.h>
+#include <json.h>
+
+cJSON*
+json_create_new_command_object(char* command_name, bool success, char* executable_name)
+{
+   // root of the JSON structure
+   cJSON* json = cJSON_CreateObject();
+
+   if (!json)
+   {
+      goto error;
+   }
+
+   // the command structure
+   cJSON* command = cJSON_CreateObject();
+   if (!command)
+   {
+      goto error;
+   }
+
+   // insert meta-data about the command
+   cJSON_AddStringToObject(command, JSON_TAG_COMMAND_NAME, command_name);
+   cJSON_AddStringToObject(command, JSON_TAG_COMMAND_STATUS, success ? JSON_STRING_SUCCESS : JSON_STRING_ERROR);
+   cJSON_AddNumberToObject(command, JSON_TAG_COMMAND_ERROR, success ? JSON_BOOL_SUCCESS : JSON_BOOL_ERROR);
+   cJSON_AddNumberToObject(command, JSON_TAG_COMMAND_EXIT_STATUS, success ? 0 : EXIT_STATUS_DATA_ERROR);
+
+   // the output of the command, this has to be filled by the caller
+   cJSON* output = cJSON_CreateObject();
+   if (!output)
+   {
+      goto error;
+   }
+
+   cJSON_AddItemToObject(command, JSON_TAG_COMMAND_OUTPUT, output);
+
+   // who has launched the command ?
+   cJSON* application = cJSON_CreateObject();
+   if (!application)
+   {
+      goto error;
+   }
+
+   cJSON_AddStringToObject(application, JSON_TAG_APPLICATION_NAME, executable_name);
+   cJSON_AddNumberToObject(application, JSON_TAG_APPLICATION_VERSION_MAJOR, PGAGROAL_MAJOR_VERSION);
+   cJSON_AddNumberToObject(application, JSON_TAG_APPLICATION_VERSION_MINOR, PGAGROAL_MINOR_VERSION);
+   cJSON_AddNumberToObject(application, JSON_TAG_APPLICATION_VERSION_PATCH, PGAGROAL_PATCH_VERSION);
+   cJSON_AddStringToObject(application, JSON_TAG_APPLICATION_VERSION, PGAGROAL_VERSION);
+
+   // add objects to the whole json thing
+   cJSON_AddItemToObject(json, "command", command);
+   cJSON_AddItemToObject(json, "application", application);
+
+   return json;
+
+error:
+   if (json)
+   {
+      cJSON_Delete(json);
+   }
+
+   return NULL;
+
+}
+
+cJSON*
+json_extract_command_output_object(cJSON* json)
+{
+   cJSON* command = cJSON_GetObjectItemCaseSensitive(json, JSON_TAG_COMMAND);
+   if (!command)
+   {
+      goto error;
+   }
+
+   return cJSON_GetObjectItemCaseSensitive(command, JSON_TAG_COMMAND_OUTPUT);
+
+error:
+   return NULL;
+
+}
+
+bool
+json_is_command_name_equals_to(cJSON* json, char* command_name)
+{
+   if (!json || !command_name || strlen(command_name) <= 0)
+   {
+      goto error;
+   }
+
+   cJSON* command = cJSON_GetObjectItemCaseSensitive(json, JSON_TAG_COMMAND);
+   if (!command)
+   {
+      goto error;
+   }
+
+   cJSON* cName = cJSON_GetObjectItemCaseSensitive(command, JSON_TAG_COMMAND_NAME);
+   if (!cName || !cJSON_IsString(cName) || !cName->valuestring)
+   {
+      goto error;
+   }
+
+   return !strncmp(command_name,
+                   cName->valuestring,
+                   MISC_LENGTH);
+
+error:
+   return false;
+}
+
+int
+json_set_command_object_faulty(cJSON* json, char* message, int exit_status)
+{
+   if (!json)
+   {
+      goto error;
+   }
+
+   cJSON* command = cJSON_GetObjectItemCaseSensitive(json, JSON_TAG_COMMAND);
+   if (!command)
+   {
+      goto error;
+   }
+
+   cJSON* current = cJSON_GetObjectItemCaseSensitive(command, JSON_TAG_COMMAND_STATUS);
+   if (!current)
+   {
+      goto error;
+   }
+
+   cJSON_SetValuestring(current, message);
+
+   current = cJSON_GetObjectItemCaseSensitive(command, JSON_TAG_COMMAND_ERROR);
+   if (!current)
+   {
+      goto error;
+   }
+
+   cJSON_SetIntValue(current, JSON_BOOL_ERROR);   // cannot use cJSON_SetBoolValue unless cJSON >= 1.7.16
+
+   current = cJSON_GetObjectItemCaseSensitive(command, JSON_TAG_COMMAND_EXIT_STATUS);
+   if (!current)
+   {
+      goto error;
+   }
+
+   cJSON_SetIntValue(current, exit_status);
+
+   return 0;
+
+error:
+   return 1;
+
+}
+
+bool
+json_is_command_object_faulty(cJSON* json)
+{
+   if (!json)
+   {
+      goto error;
+   }
+
+   cJSON* command = cJSON_GetObjectItemCaseSensitive(json, JSON_TAG_COMMAND);
+   if (!command)
+   {
+      goto error;
+   }
+
+   cJSON* status = cJSON_GetObjectItemCaseSensitive(command, JSON_TAG_COMMAND_ERROR);
+   if (!status || !cJSON_IsNumber(status))
+   {
+      goto error;
+   }
+
+   return status->valueint == JSON_BOOL_SUCCESS ? false : true;
+
+error:
+   return false;
+
+}
+
+int
+json_command_object_exit_status(cJSON* json)
+{
+   if (!json)
+   {
+      goto error;
+   }
+
+   cJSON* command = cJSON_GetObjectItemCaseSensitive(json, JSON_TAG_COMMAND);
+   if (!command)
+   {
+      goto error;
+   }
+
+   cJSON* status = cJSON_GetObjectItemCaseSensitive(command, JSON_TAG_COMMAND_EXIT_STATUS);
+   if (!status || !cJSON_IsNumber(status))
+   {
+      goto error;
+   }
+
+   return status->valueint;
+
+error:
+   return EXIT_STATUS_DATA_ERROR;
+}
+
+const char*
+json_get_command_object_status(cJSON* json)
+{
+   if (!json)
+   {
+      goto error;
+   }
+
+   cJSON* command = cJSON_GetObjectItemCaseSensitive(json, JSON_TAG_COMMAND);
+   if (!command)
+   {
+      goto error;
+   }
+
+   cJSON* status = cJSON_GetObjectItemCaseSensitive(command, JSON_TAG_COMMAND_STATUS);
+   if (!cJSON_IsString(status) || (status->valuestring == NULL))
+   {
+      goto error;
+   }
+
+   return status->valuestring;
+error:
+   return NULL;
+
+}
+
+void
+json_print_and_free_json_object(cJSON* json)
+{
+   printf("%s\n", cJSON_Print(json));
+   cJSON_Delete(json);
+}
diff --git a/src/libpgagroal/management.c b/src/libpgagroal/management.c
index 3dd4719e..647e18fe 100644
--- a/src/libpgagroal/management.c
+++ b/src/libpgagroal/management.c
@@ -35,6 +35,7 @@
 #include <pool.h>
 #include <utils.h>
 #include <configuration.h>
+#include <json.h>
 
 /* system */
 #include <errno.h>
@@ -62,6 +63,14 @@ static int write_header(SSL* ssl, int fd, signed char type, int slot);
 static int pgagroal_management_write_conf_ls_detail(int socket, char* what);
 static int pgagroal_management_read_conf_ls_detail(SSL* ssl, int socket, char* buffer);
 
+static int pgagroal_management_json_print_status_details(cJSON* json);
+
+static cJSON* pgagroal_management_json_read_status_details(SSL* ssl, int socket, bool include_details);
+static cJSON* pgagroal_managment_json_read_config_get(int socket, char* config_key, char* expected_value);
+
+static cJSON* pgagroal_management_json_read_conf_ls(SSL* ssl, int socket);
+static int pgagroal_management_json_print_conf_ls(cJSON* json);
+
 int
 pgagroal_management_read_header(int socket, signed char* id, int32_t* slot)
 {
@@ -560,7 +569,50 @@ pgagroal_management_status(SSL* ssl, int fd)
 }
 
 int
-pgagroal_management_read_status(SSL* ssl, int socket)
+pgagroal_management_read_status(SSL* ssl, int socket, char output_format)
+{
+   cJSON* json = pgagroal_management_json_read_status_details(ssl, socket, false);
+
+   // check we have an answer and it is not an error
+   if (!json || json_is_command_object_faulty(json))
+   {
+      goto error;
+   }
+
+   // print out the command answer
+   if (output_format == COMMAND_OUTPUT_FORMAT_JSON)
+   {
+      json_print_and_free_json_object(json);
+   }
+   else
+   {
+      pgagroal_management_json_print_status_details(json);
+   }
+
+   return 0;
+
+error:
+   pgagroal_log_warn("pgagroal_management_read_status: command error [%s]",
+                     (json == NULL ? "<unknown>" : json_get_command_object_status(json)));
+   return 1;
+}
+
+/**
+ * Utility method that reads the answer from pgagroal about
+ * either the 'status' or the 'status details' command.
+ * The answer is then wrapped into a JSON object
+ * that contains all the information needed to be printed out in either
+ * JSON format or text format.
+ *
+ * @param ssl the SSL file descriptor for the socket
+ * @param socket the socket file descriptor
+ * @param include_details true if the method has to handle the 'status details' command
+ * or false if the answer is related only to the 'status' command
+ *
+ * @returns the json object, faulty if something goes wrong
+ */
+static cJSON*
+pgagroal_management_json_read_status_details(SSL* ssl, int socket, bool include_details)
 {
    char buf[16];
    char disabled[NUMBER_OF_DISABLED][MAX_DATABASE_LENGTH];
@@ -568,21 +620,27 @@ pgagroal_management_read_status(SSL* ssl, int socket)
    int active;
    int total;
    int max;
+   int max_connections = 0;
+   int limits = 0;
+   int servers = 0;
+   char header[12 + MAX_NUMBER_OF_CONNECTIONS];
 
    memset(&buf, 0, sizeof(buf));
    memset(&disabled, 0, sizeof(disabled));
+   memset(&header, 0, sizeof(header));
+
+   cJSON* json = json_create_new_command_object(include_details ? "status details" :  "status", true, "pgagroal-cli");
+   cJSON* output = json_extract_command_output_object(json);
 
    if (read_complete(ssl, socket, &buf[0], sizeof(buf)))
    {
-      pgagroal_log_warn("pgagroal_management_read_status: read: %d %s", socket, strerror(errno));
-      errno = 0;
+      pgagroal_log_warn("pgagroal_management_json_read_status_details: read: %d %s", socket, strerror(errno));
       goto error;
    }
 
    if (read_complete(ssl, socket, &disabled[0], sizeof(disabled)))
    {
-      pgagroal_log_warn("pgagroal_management_read_status: read: %d %s", socket, strerror(errno));
-      errno = 0;
+      pgagroal_log_warn("pgagroal_management_json_read_status_details: read: %d %s", socket, strerror(errno));
       goto error;
    }
 
@@ -591,10 +649,24 @@ pgagroal_management_read_status(SSL* ssl, int socket)
    total = pgagroal_read_int32(&(buf[8]));
    max = pgagroal_read_int32(&(buf[12]));
 
-   printf("Status:              %s\n", (status == 1 ? "Running" : "Graceful shutdown"));
-   printf("Active connections:  %d\n", active);
-   printf("Total connections:   %d\n", total);
-   printf("Max connections:     %d\n", max);
+   // status information
+   cJSON* status_json = cJSON_CreateObject();
+   cJSON_AddStringToObject(status_json, "message", (status == 1 ? "Running" : "Graceful shutdown"));
+   cJSON_AddNumberToObject(status_json, "status", status);
+   cJSON_AddItemToObject(output, "status", status_json);
+
+   // define all the information about connections
+   cJSON* connections = cJSON_CreateObject();
+   cJSON_AddNumberToObject(connections, "active", active);
+   cJSON_AddNumberToObject(connections, "total", total);
+   cJSON_AddNumberToObject(connections, "max", max);
+   cJSON_AddItemToObject(output, "connections", connections);
+
+   // define all the information about disabled databases
+   cJSON* databases = cJSON_CreateObject();
+   cJSON* databases_array = cJSON_CreateArray();
+
+   int counter = 0;
 
    for (int i = 0; i < NUMBER_OF_DISABLED; i++)
    {
@@ -602,20 +674,165 @@ pgagroal_management_read_status(SSL* ssl, int socket)
       {
          if (!strcmp(disabled[i], "*"))
          {
-            printf("Disabled database:   ALL\n");
+            cJSON_AddItemToArray(databases_array, cJSON_CreateString("ALL"));
+            counter = -1;
          }
          else
          {
-            printf("Disabled database:   %s\n", disabled[i]);
+            cJSON_AddItemToArray(databases_array, cJSON_CreateString(disabled[i]));
+            counter++;
          }
       }
    }
 
-   return 0;
+   cJSON* disabled_databases = cJSON_CreateObject();
+   cJSON_AddNumberToObject(disabled_databases, "count", counter);
+   cJSON_AddStringToObject(disabled_databases, "state", "disabled");
+   cJSON_AddItemToObject(disabled_databases, JSON_TAG_ARRAY_NAME, databases_array);
+   cJSON_AddItemToObject(databases, "disabled", disabled_databases);
+   cJSON_AddItemToObject(output, "databases", databases);
 
-error:
+   // the 'status' command ends here
+   if (!include_details)
+   {
+      goto end;
+   }
 
-   return 1;
+   /*********** 'status details ************/
+
+   memset(&header, 0, sizeof(header));
+
+   if (read_complete(ssl, socket, &header[0], sizeof(header)))
+   {
+      goto error;
+   }
+
+   // quantity informations
+   max_connections = pgagroal_read_int32(&header);
+   limits = pgagroal_read_int32(&(header[4]));
+   servers = pgagroal_read_int32(&(header[8]));
+
+   cJSON* json_servers = cJSON_CreateObject();
+   cJSON* json_servers_array = cJSON_CreateArray();
+   cJSON_AddItemToObject(output, "servers", json_servers);
+   cJSON_AddNumberToObject(json_servers, "count", servers);
+
+   // details about the servers
+   for (int i = 0; i < servers; i++)
+   {
+      char server[5 + MISC_LENGTH + MISC_LENGTH];
+
+      memset(&server, 0, sizeof(server));
+
+      if (read_complete(ssl, socket, &server[0], sizeof(server)))
+      {
+         goto error;
+      }
+
+      cJSON* current_server_json = cJSON_CreateObject();
+      cJSON_AddStringToObject(current_server_json, "server", pgagroal_read_string(&(server[0])));
+      cJSON_AddStringToObject(current_server_json, "host", pgagroal_read_string(&(server[MISC_LENGTH])));
+      cJSON_AddNumberToObject(current_server_json, "port", pgagroal_read_int32(&(server[MISC_LENGTH + MISC_LENGTH])));
+      cJSON_AddStringToObject(current_server_json, "state", pgagroal_server_state_as_string(pgagroal_read_byte(&(server[MISC_LENGTH + MISC_LENGTH + 4]))));
+
+      cJSON_AddItemToArray(json_servers_array, current_server_json);
+   }
+
+   cJSON_AddItemToObject(json_servers, JSON_TAG_ARRAY_NAME, json_servers_array);
+
+   // details about the limits
+   cJSON* json_limits = cJSON_CreateObject();
+   cJSON* json_limits_array = cJSON_CreateArray();
+   cJSON_AddItemToObject(json_limits, JSON_TAG_ARRAY_NAME, json_limits_array);
+   cJSON_AddItemToObject(output, "limits", json_limits);
+   cJSON_AddNumberToObject(json_limits, "count", limits);
+
+   for (int i = 0; i < limits; i++)
+   {
+      char limit[16 + MAX_DATABASE_LENGTH + MAX_USERNAME_LENGTH];
+      memset(&limit, 0, sizeof(limit));
+
+      if (read_complete(ssl, socket, &limit[0], sizeof(limit)))
+      {
+         goto error;
+      }
+
+      cJSON* current_limit_json = cJSON_CreateObject();
+
+      cJSON_AddStringToObject(current_limit_json, "database", pgagroal_read_string(&(limit[16])));
+      cJSON_AddStringToObject(current_limit_json, "username", pgagroal_read_string(&(limit[16 + MAX_DATABASE_LENGTH])));
+
+      cJSON* current_connections = cJSON_CreateObject();
+
+      cJSON_AddNumberToObject(current_connections, "active", pgagroal_read_int32(&(limit)));
+      cJSON_AddNumberToObject(current_connections, "max", pgagroal_read_int32(&(limit[4])));
+      cJSON_AddNumberToObject(current_connections, "initial", pgagroal_read_int32(&(limit[8])));
+      cJSON_AddNumberToObject(current_connections, "min", pgagroal_read_int32(&(limit[12])));
+
+      cJSON_AddItemToObject(current_limit_json, "connections", current_connections);
+      cJSON_AddItemToArray(json_limits_array, current_limit_json);
+
+   }
+
+   // max connections details (note that the connections json object has been created
+   // as part of the status output)
+   cJSON* connections_array = cJSON_CreateArray();
+   cJSON_AddItemToObject(connections, JSON_TAG_ARRAY_NAME, connections_array);
+
+   for (int i = 0; i < max_connections; i++)
+   {
+      char details[16 + MAX_DATABASE_LENGTH + MAX_USERNAME_LENGTH + MAX_APPLICATION_NAME];
+      signed char state;
+      long time;
+      time_t t;
+      char ts[20] = {0};
+      int pid;
+      char p[10] = {0};
+      int fd;
+      char f[10] = {0};
+
+      memset(&details, 0, sizeof(details));
+
+      if (read_complete(ssl, socket, &details[0], sizeof(details)))
+      {
+
+         goto error;
+      }
+
+      state = (signed char)header[12 + i];
+      time = pgagroal_read_long(&(details[0]));
+      pid = pgagroal_read_int32(&(details[8]));
+      fd = pgagroal_read_int32(&(details[12]));
+
+      t = time;
+      strftime(ts, 20, "%Y-%m-%d %H:%M:%S", localtime(&t));
+
+      sprintf(p, "%d", pid);
+      sprintf(f, "%d", fd);
+
+      cJSON* current_connection_json = cJSON_CreateObject();
+
+      cJSON_AddNumberToObject(current_connection_json, "number", i);
+      cJSON_AddStringToObject(current_connection_json, "state", pgagroal_server_state_as_string(state));
+      cJSON_AddStringToObject(current_connection_json, "time", time > 0 ? ts : "");
+      cJSON_AddStringToObject(current_connection_json, "pid", pid > 0 ? p : "");
+      cJSON_AddStringToObject(current_connection_json, "fd", fd > 0 ? f : "");
+      cJSON_AddStringToObject(current_connection_json, "database", pgagroal_read_string(&(details[16])));
+      cJSON_AddStringToObject(current_connection_json, "user", pgagroal_read_string(&(details[16 + MAX_DATABASE_LENGTH])));
+      cJSON_AddStringToObject(current_connection_json, "detail", pgagroal_read_string(&(details[16 + MAX_DATABASE_LENGTH + MAX_USERNAME_LENGTH])));
+
+      cJSON_AddItemToArray(connections_array, current_connection_json);
+
+   }
+
+end:
+   return json;
+
+error:
+   // set the json object as faulty and erase the errno
+   json_set_command_object_faulty(json, strerror(errno), errno);
+   errno = 0;
+   return json;
 }
 
 int
@@ -706,143 +923,31 @@ pgagroal_management_details(SSL* ssl, int fd)
 }
 
 int
-pgagroal_management_read_details(SSL* ssl, int socket)
+pgagroal_management_read_details(SSL* ssl, int socket, char output_format)
 {
-   char header[12 + MAX_NUMBER_OF_CONNECTIONS];
-   int max_connections = 0;
-   int limits = 0;
-   int servers = 0;
+   cJSON* json = pgagroal_management_json_read_status_details(ssl, socket, true);
 
-   memset(&header, 0, sizeof(header));
-
-   if (read_complete(ssl, socket, &header[0], sizeof(header)))
+   // check we have an answer and it is not an error
+   if (!json || json_is_command_object_faulty(json))
    {
-      pgagroal_log_warn("pgagroal_management_read_details: read: %d %s", socket, strerror(errno));
-      errno = 0;
       goto error;
    }
 
-   max_connections = pgagroal_read_int32(&header);
-   limits = pgagroal_read_int32(&(header[4]));
-   servers = pgagroal_read_int32(&(header[8]));
-
-   for (int i = 0; i < servers; i++)
+   // print out the command answer
+   if (output_format == COMMAND_OUTPUT_FORMAT_JSON)
    {
-      char server[5 + MISC_LENGTH + MISC_LENGTH];
-      signed char state;
-
-      memset(&server, 0, sizeof(server));
-
-      if (read_complete(ssl, socket, &server[0], sizeof(server)))
-      {
-         pgagroal_log_warn("pgagroal_management_read_details: read: %d %s", socket, strerror(errno));
-         errno = 0;
-         goto error;
-      }
-
-      state = pgagroal_read_byte(&(server[MISC_LENGTH + MISC_LENGTH + 4]));
-
-      printf("---------------------\n");
-      printf("Server:              %s\n", pgagroal_read_string(&(server[0])));
-      printf("Host:                %s\n", pgagroal_read_string(&(server[MISC_LENGTH])));
-      printf("Port:                %d\n", pgagroal_read_int32(&(server[MISC_LENGTH + MISC_LENGTH])));
-
-      switch (state)
-      {
-         case SERVER_NOTINIT:
-            printf("State:               Not init\n");
-            break;
-         case SERVER_NOTINIT_PRIMARY:
-            printf("State:               Not init (primary)\n");
-            break;
-         case SERVER_PRIMARY:
-            printf("State:               Primary\n");
-            break;
-         case SERVER_REPLICA:
-            printf("State:               Replica\n");
-            break;
-         case SERVER_FAILOVER:
-            printf("State:               Failover\n");
-            break;
-         case SERVER_FAILED:
-            printf("State:               Failed\n");
-            break;
-         default:
-            printf("State:               %d\n", state);
-            break;
-      }
-   }
-
-   printf("---------------------\n");
-
-   for (int i = 0; i < limits; i++)
-   {
-      char limit[16 + MAX_DATABASE_LENGTH + MAX_USERNAME_LENGTH];
-
-      memset(&limit, 0, sizeof(limit));
-
-      if (read_complete(ssl, socket, &limit[0], sizeof(limit)))
-      {
-         pgagroal_log_warn("pgagroal_management_read_details: read: %d %s", socket, strerror(errno));
-         errno = 0;
-         goto error;
-      }
-
-      printf("Database:            %s\n", pgagroal_read_string(&(limit[16])));
-      printf("Username:            %s\n", pgagroal_read_string(&(limit[16 + MAX_DATABASE_LENGTH])));
-      printf("Active connections:  %d\n", pgagroal_read_int32(&(limit)));
-      printf("Max connections:     %d\n", pgagroal_read_int32(&(limit[4])));
-      printf("Initial connections: %d\n", pgagroal_read_int32(&(limit[8])));
-      printf("Min connections:     %d\n", pgagroal_read_int32(&(limit[12])));
-      printf("---------------------\n");
+      json_print_and_free_json_object(json);
    }
-
-   for (int i = 0; i < max_connections; i++)
+   else
    {
-      char details[16 + MAX_DATABASE_LENGTH + MAX_USERNAME_LENGTH + MAX_APPLICATION_NAME];
-      signed char state;
-      long time;
-      time_t t;
-      char ts[20] = {0};
-      int pid;
-      char p[10] = {0};
-      int fd;
-      char f[10] = {0};
-
-      memset(&details, 0, sizeof(details));
-
-      if (read_complete(ssl, socket, &details[0], sizeof(details)))
-      {
-         pgagroal_log_warn("pgagroal_management_read_details: read: %d %s", socket, strerror(errno));
-         errno = 0;
-         goto error;
-      }
-
-      state = (signed char)header[12 + i];
-      time = pgagroal_read_long(&(details[0]));
-      pid = pgagroal_read_int32(&(details[8]));
-      fd = pgagroal_read_int32(&(details[12]));
-
-      t = time;
-      strftime(ts, 20, "%Y-%m-%d %H:%M:%S", localtime(&t));
-
-      sprintf(p, "%d", pid);
-      sprintf(f, "%d", fd);
-
-      printf("Connection %4d:     %-15s %-19s %-6s %-6s %s %s %s\n",
-             i,
-             pgagroal_get_state_string(state),
-             time > 0 ? ts : "",
-             pid > 0 ? p : "",
-             fd > 0 ? f : "",
-             pgagroal_read_string(&(details[16])),
-             pgagroal_read_string(&(details[16 + MAX_DATABASE_LENGTH])),
-             pgagroal_read_string(&(details[16 + MAX_DATABASE_LENGTH + MAX_USERNAME_LENGTH])));
+      pgagroal_management_json_print_status_details(json);
    }
 
    return 0;
 
 error:
+   pgagroal_log_warn("pgagroal_management_read_details: command error [%s]",
+                     (json == NULL ? "<unknown>" : json_get_command_object_status(json)));
 
    return 1;
 }
@@ -962,7 +1067,7 @@ pgagroal_management_isalive(SSL* ssl, int fd)
 }
 
 int
-pgagroal_management_read_isalive(SSL* ssl, int socket, int* status)
+pgagroal_management_read_isalive(SSL* ssl, int socket, int* status, char output_format)
 {
    char buf[4];
 
@@ -977,6 +1082,31 @@ pgagroal_management_read_isalive(SSL* ssl, int socket, int* status)
 
    *status = pgagroal_read_int32(&buf);
 
+   // do I need to provide JSON output?
+   if (output_format == COMMAND_OUTPUT_FORMAT_JSON)
+   {
+      cJSON* json = json_create_new_command_object("ping", true, "pgagroal-cli");
+      cJSON* output = json_extract_command_output_object(json);
+
+      cJSON_AddNumberToObject(output, "status", *status);
+
+      if (*status == PING_STATUS_RUNNING)
+      {
+         cJSON_AddStringToObject(output, "message", "running");
+      }
+      else if (*status == PING_STATUS_SHUTDOWN_GRACEFULLY)
+      {
+         cJSON_AddStringToObject(output, "message", "shutdown gracefully");
+      }
+      else
+      {
+         cJSON_AddStringToObject(output, "message", "unknown");
+      }
+
+      json_print_and_free_json_object(json);
+
+   }
+
    return 0;
 
 error:
@@ -993,11 +1123,11 @@ pgagroal_management_write_isalive(int socket, bool gracefully)
 
    if (!gracefully)
    {
-      pgagroal_write_int32(buf, 1);
+      pgagroal_write_int32(buf, PING_STATUS_RUNNING);
    }
    else
    {
-      pgagroal_write_int32(buf, 2);
+      pgagroal_write_int32(buf, PING_STATUS_SHUTDOWN_GRACEFULLY);
    }
 
    if (write_complete(NULL, socket, &buf, sizeof(buf)))
@@ -1608,11 +1738,105 @@ pgagroal_management_write_config_get(int socket, char* config_key)
 
 }
 
-int
-pgagroal_management_read_config_get(int socket, char** data)
+/**
+ * Utility method to wrap the answer about a configuration setting
+ * into a JSON object.
+ *
+ * @param socket the socket from which reading the data from
+ * @param config_key the key requested, used only to populate the json
+ * @param expected_value the config value expected in the case of a `config set`.
+ * If the expetced_value is not null, the function checks if the obtained config value and
+ * the expected one are equal, and in case are not set the JSON object as faulty.
+ *
+ * @return the JSON object
+ */
+static cJSON*
+pgagroal_managment_json_read_config_get(int socket, char* config_key, char* expected_value)
 {
+
    int size = MISC_LENGTH;
-   return pgagroal_management_read_payload(socket, MANAGEMENT_CONFIG_GET, &size, data);
+   char* buffer = NULL;
+   bool is_config_set = false;
+
+   buffer = calloc(1, size);
+   if (buffer == NULL)
+   {
+      goto error;
+   }
+
+   if (pgagroal_management_read_payload(socket, MANAGEMENT_CONFIG_GET, &size, &buffer))
+   {
+      goto error;
+   }
+
+   // is this the answer from a 'conf set' command ?
+   is_config_set = (expected_value && strlen(expected_value) > 0);
+
+   cJSON* json = json_create_new_command_object(is_config_set ? "conf set" :  "conf get", true, "pgagroal-cli");
+   cJSON* output = json_extract_command_output_object(json);
+   cJSON_AddStringToObject(output, "key", config_key);
+   cJSON_AddStringToObject(output, "value", buffer);
+
+   if (is_config_set)
+   {
+      cJSON_AddStringToObject(output, "expected", expected_value);
+
+      // if the expected value is not what we get, this means there is an error
+      // (e.g., cannot apply the config set)
+      if (strncmp(buffer, expected_value, size))
+      {
+         json_set_command_object_faulty(json, "Current and expected values are different", EXIT_STATUS_DATA_ERROR);
+      }
+   }
+
+   free(buffer);
+   return json;
+error:
+   if (buffer)
+   {
+      free(buffer);
+   }
+   return NULL;
+}
+
+int
+pgagroal_management_read_config_get(int socket, char* config_key, char* expected_value, bool verbose, char output_format)
+{
+
+   cJSON* json = pgagroal_managment_json_read_config_get(socket, config_key, expected_value);
+
+   if (!json)
+   {
+      goto error;
+   }
+
+   if (output_format == COMMAND_OUTPUT_FORMAT_JSON)
+   {
+      json_print_and_free_json_object(json);
+      goto end;
+   }
+
+   // if here, print out in text format
+   cJSON* output = json_extract_command_output_object(json);
+   cJSON* value = cJSON_GetObjectItemCaseSensitive(output, "value");
+   cJSON* key = cJSON_GetObjectItemCaseSensitive(output, "key");
+   if (verbose)
+   {
+      printf("%s = %s\n", key->valuestring, value->valuestring);
+   }
+   else
+   {
+      printf("%s\n", value->valuestring);
+   }
+
+end:
+   return json_command_object_exit_status(json);
+
+error:
+
+   pgagroal_log_warn("pgagroal_management_read_config_get : error retrieving configuration for <%s> : %s", config_key, strerror(errno));
+   errno = 0;
+   return EXIT_STATUS_DATA_ERROR;
 }
 
 int
@@ -1750,69 +1974,31 @@ pgagroal_management_conf_ls(SSL* ssl, int fd)
 }
 
 int
-pgagroal_management_read_conf_ls(SSL* ssl, int socket)
+pgagroal_management_read_conf_ls(SSL* ssl, int socket, char output_format)
 {
-   char buf[4];
-   char* buffer;
-
-   memset(&buf, 0, sizeof(buf));
-   buffer = calloc(1, MAX_PATH);
-
-   if (pgagroal_management_read_conf_ls_detail(ssl, socket, buffer))
-   {
-      goto error;
-   }
 
-   printf("Main Configuration file:   %s\n", buffer);
+   // get the JSON output
+   cJSON* json = pgagroal_management_json_read_conf_ls(ssl, socket);
 
-   if (pgagroal_management_read_conf_ls_detail(ssl, socket, buffer))
+   // check we have an answer and it is not an error
+   if (!json || json_is_command_object_faulty(json))
    {
       goto error;
    }
 
-   printf("HBA file:                  %s\n", buffer);
-
-   if (pgagroal_management_read_conf_ls_detail(ssl, socket, buffer))
+   // print out the command answer
+   if (output_format == COMMAND_OUTPUT_FORMAT_JSON)
    {
-      goto error;
+      json_print_and_free_json_object(json);
    }
-
-   printf("Limit file:                %s\n", buffer);
-
-   if (pgagroal_management_read_conf_ls_detail(ssl, socket, buffer))
-   {
-      goto error;
-   }
-
-   printf("Frontend users file:       %s\n", buffer);
-
-   if (pgagroal_management_read_conf_ls_detail(ssl, socket, buffer))
-   {
-      goto error;
-   }
-
-   printf("Admins file:               %s\n", buffer);
-
-   if (pgagroal_management_read_conf_ls_detail(ssl, socket, buffer))
-   {
-      goto error;
-   }
-
-   printf("Superuser file:            %s\n", buffer);
-
-   if (pgagroal_management_read_conf_ls_detail(ssl, socket, buffer))
+   else
    {
-      goto error;
+      pgagroal_management_json_print_conf_ls(json);
    }
 
-   printf("Users file:                %s\n", buffer);
-
-   free(buffer);
-
    return 0;
 
 error:
-   free(buffer);
    pgagroal_log_warn("pgagroal_management_read_conf_ls: read: %d %s", socket, strerror(errno));
    errno = 0;
 
@@ -1971,3 +2157,308 @@ pgagroal_management_read_conf_ls_detail(SSL* ssl, int socket, char* buffer)
 
    return 1;
 }
+
+/**
+ * Utility function to print out the result of a 'status'
+ * or a 'status details' command already wrapped into a
+ * JSON object.
+ * The function tries to understand from the command name
+ * within the JSON object if the output refers to the
+ * 'status' or 'status details' command.
+ *
+ * If the command is faulty, this method does nothing, therefore
+ * printing out information about faulty commands has to be done
+ * at an higher level.
+ *
+ * @param json the JSON object
+ *
+ * @returns 0 on success
+ */
+int
+pgagroal_management_json_print_status_details(cJSON* json)
+{
+   bool is_command_details = false; /* is this command 'status details' ? */
+
+   // sanity check
+   if (!json || json_is_command_object_faulty(json))
+   {
+      return 1;
+   }
+
+   // the command must be 'status' or 'status details'
+   if (json_is_command_name_equals_to(json, "status"))
+   {
+      is_command_details = false;
+   }
+   else if (json_is_command_name_equals_to(json, "status details"))
+   {
+      is_command_details = true;
+   }
+   else
+   {
+      goto error;
+   }
+
+   // now get the output and start printing it
+   cJSON* output = json_extract_command_output_object(json);
+
+   // overall status
+   printf("Status:              %s\n",
+          cJSON_GetObjectItemCaseSensitive(cJSON_GetObjectItemCaseSensitive(output, "status"), "message")->valuestring);
+
+   // connections
+   cJSON* connections = cJSON_GetObjectItemCaseSensitive(output, "connections");
+   if (!connections)
+   {
+      goto error;
+   }
+
+   printf("Active connections:  %d\n", cJSON_GetObjectItemCaseSensitive(connections, "active")->valueint);
+   printf("Total connections:   %d\n", cJSON_GetObjectItemCaseSensitive(connections, "total")->valueint);
+   printf("Max connections:     %d\n", cJSON_GetObjectItemCaseSensitive(connections, "max")->valueint);
+
+   // databases
+   cJSON* databases = cJSON_GetObjectItemCaseSensitive(output, "databases");
+   if (!databases)
+   {
+      goto error;
+   }
+
+   cJSON* disabled_databases = cJSON_GetObjectItemCaseSensitive(databases, "disabled");
+   if (!disabled_databases)
+   {
+      goto error;
+   }
+
+   cJSON* disabled_databases_list = cJSON_GetObjectItemCaseSensitive(disabled_databases, JSON_TAG_ARRAY_NAME);
+   cJSON* current;
+   cJSON_ArrayForEach(current, disabled_databases_list)
+   {
+      printf("Disabled database:   %s\n", current->valuestring);
+   }
+
+   // the status command ends here
+   if (!is_command_details)
+   {
+      goto end;
+   }
+
+   // dump the servers information
+   cJSON* servers = cJSON_GetObjectItemCaseSensitive(output, "servers");
+   if (!servers)
+   {
+      goto error;
+   }
+
+   cJSON* servers_list = cJSON_GetObjectItemCaseSensitive(servers, JSON_TAG_ARRAY_NAME);
+   cJSON_ArrayForEach(current, servers_list)
+   {
+      printf("---------------------\n");
+      printf("Server:              %s\n", cJSON_GetObjectItemCaseSensitive(current, "server")->valuestring);
+      printf("Host:                %s\n", cJSON_GetObjectItemCaseSensitive(current, "host")->valuestring);
+      printf("Port:                %d\n", cJSON_GetObjectItemCaseSensitive(current, "port")->valueint);
+      printf("State:               %s\n", cJSON_GetObjectItemCaseSensitive(current, "state")->valuestring);
+      printf("---------------------\n");
+
+   }
+
+   // dump the limits information
+   cJSON* limits = cJSON_GetObjectItemCaseSensitive(output, "limits");
+   cJSON* limits_list = cJSON_GetObjectItemCaseSensitive(limits, JSON_TAG_ARRAY_NAME);
+   cJSON_ArrayForEach(current, limits_list)
+   {
+      printf("---------------------\n");
+      printf("Database:            %s\n", cJSON_GetObjectItemCaseSensitive(current, "database")->valuestring);
+      printf("Username:            %s\n", cJSON_GetObjectItemCaseSensitive(current, "username")->valuestring);
+      cJSON* current_connections = cJSON_GetObjectItemCaseSensitive(current, "connections");
+      printf("Active connections:  %d\n", cJSON_GetObjectItemCaseSensitive(current_connections, "active")->valueint);
+      printf("Max connections:     %d\n", cJSON_GetObjectItemCaseSensitive(current_connections, "max")->valueint);
+      printf("Initial connections: %d\n", cJSON_GetObjectItemCaseSensitive(current_connections, "initial")->valueint);
+      printf("Min connections:     %d\n", cJSON_GetObjectItemCaseSensitive(current_connections, "min")->valueint);
+      printf("---------------------\n");
+   }
+
+   // print the connection information
+   int i = 0;
+   cJSON_ArrayForEach(current, cJSON_GetObjectItemCaseSensitive(connections, JSON_TAG_ARRAY_NAME))
+   {
+      printf("Connection %4d:     %-15s %-19s %-6s %-6s %s %s %s\n",
+             i++,
+             cJSON_GetObjectItemCaseSensitive(current, "state")->valuestring,
+             cJSON_GetObjectItemCaseSensitive(current, "time")->valuestring,
+             cJSON_GetObjectItemCaseSensitive(current, "pid")->valuestring,
+             cJSON_GetObjectItemCaseSensitive(current, "fd")->valuestring,
+             cJSON_GetObjectItemCaseSensitive(current, "user")->valuestring,
+             cJSON_GetObjectItemCaseSensitive(current, "database")->valuestring,
+             cJSON_GetObjectItemCaseSensitive(current, "detail")->valuestring);
+
+   }
+
+end:
+   return 0;
+
+error:
+   return 1;
+
+}
+
+/**
+ * Utility method to get the information about the `conf ls` command.
+ * This method produces a cJSON object that needs to be printed out in textual format.
+ *
+ * @param ssl the SSL file descriptor
+ * @param socket the file descriptor for the socket
+ *
+ * @returns the cJSON object, faulty if something went wrong
+ */
+static cJSON*
+pgagroal_management_json_read_conf_ls(SSL* ssl, int socket)
+{
+   char buf[4];
+   char* buffer;
+
+   cJSON* json = json_create_new_command_object("conf ls", true, "pgagroal-cli");
+   cJSON* output = json_extract_command_output_object(json);
+
+   // add an array that will contain the files
+   cJSON* files = cJSON_CreateObject();
+   cJSON* files_array = cJSON_CreateArray();
+   cJSON_AddItemToObject(output, "files", files);
+   cJSON_AddItemToObject(files, JSON_TAG_ARRAY_NAME, files_array);
+   //             cJSON_AddItemToArray(databases_array, cJSON_CreateString("ALL"));
+
+   memset(&buf, 0, sizeof(buf));
+   buffer = calloc(1, MAX_PATH);
+
+   if (pgagroal_management_read_conf_ls_detail(ssl, socket, buffer))
+   {
+      goto error;
+   }
+
+   // add the main configuration file entry
+   cJSON* mainConf = cJSON_CreateObject();
+   cJSON_AddStringToObject(mainConf, "description", "Main Configuration file");
+   cJSON_AddStringToObject(mainConf, "path", buffer);
+   cJSON_AddItemToArray(files_array, mainConf);
+
+   if (pgagroal_management_read_conf_ls_detail(ssl, socket, buffer))
+   {
+      goto error;
+   }
+
+   // add the HBA file
+   cJSON* hbaConf = cJSON_CreateObject();
+   cJSON_AddStringToObject(hbaConf, "description", "HBA File");
+   cJSON_AddStringToObject(hbaConf, "path", buffer);
+   cJSON_AddItemToArray(files_array, hbaConf);
+
+   if (pgagroal_management_read_conf_ls_detail(ssl, socket, buffer))
+   {
+      goto error;
+   }
+
+   // add the limit file
+   cJSON* limitConf = cJSON_CreateObject();
+   cJSON_AddStringToObject(limitConf, "description", "Limit file");
+   cJSON_AddStringToObject(limitConf, "path", buffer);
+   cJSON_AddItemToArray(files_array, limitConf);
+
+   if (pgagroal_management_read_conf_ls_detail(ssl, socket, buffer))
+   {
+      goto error;
+   }
+
+   // add the frontend file
+   cJSON* frontendConf = cJSON_CreateObject();
+   cJSON_AddStringToObject(frontendConf, "description", "Frontend users file");
+   cJSON_AddStringToObject(frontendConf, "path", buffer);
+   cJSON_AddItemToArray(files_array, frontendConf);
+
+   if (pgagroal_management_read_conf_ls_detail(ssl, socket, buffer))
+   {
+      goto error;
+   }
+
+   // add the admins file
+   cJSON* adminsConf = cJSON_CreateObject();
+   cJSON_AddStringToObject(adminsConf, "description", "Admins file");
+   cJSON_AddStringToObject(adminsConf, "path", buffer);
+   cJSON_AddItemToArray(files_array, adminsConf);
+
+   if (pgagroal_management_read_conf_ls_detail(ssl, socket, buffer))
+   {
+      goto error;
+   }
+
+   // add the superuser file
+   cJSON* superuserConf = cJSON_CreateObject();
+   cJSON_AddStringToObject(superuserConf, "description", "Superuser file");
+   cJSON_AddStringToObject(superuserConf, "path", buffer);
+   cJSON_AddItemToArray(files_array, superuserConf);
+
+   if (pgagroal_management_read_conf_ls_detail(ssl, socket, buffer))
+   {
+      goto error;
+   }
+
+   // add the users file
+   cJSON* usersConf = cJSON_CreateObject();
+   cJSON_AddStringToObject(usersConf, "description", "Users file");
+   cJSON_AddStringToObject(usersConf, "path", buffer);
+   cJSON_AddItemToArray(files_array, usersConf);
+
+   // all done
+   goto end;
+
+error:
+   free(buffer);
+   pgagroal_log_warn("pgagroal_management_json_read_conf_ls: read: %d %s", socket, strerror(errno));
+   errno = 0;
+   json_set_command_object_faulty(json, strerror(errno), errno);
+
+end:
+   free(buffer);
+   return json;
+
+}
+
+/**
+ * Utility function to handle a JSON object and print it out
+ * as normal text.
+ *
+ * @param json the JSON object
+ * @returns 0 on success
+ */
+static int
+pgagroal_management_json_print_conf_ls(cJSON* json)
+{
+   // sanity check
+   if (!json || json_is_command_object_faulty(json))
+   {
+      goto error;
+   }
+
+   // now get the output and start printing it
+   cJSON* output = json_extract_command_output_object(json);
+
+   // files
+   cJSON* files = cJSON_GetObjectItemCaseSensitive(output, "files");
+   if (!files)
+   {
+      goto error;
+   }
+
+   cJSON* files_array = cJSON_GetObjectItemCaseSensitive(files, JSON_TAG_ARRAY_NAME);
+   cJSON* current;
+   cJSON_ArrayForEach(current, files_array)
+   {
+      // the current JSON object is made by two different values
+      printf("%-25s : %s\n",
+             cJSON_GetObjectItemCaseSensitive(current, "description")->valuestring,
+             cJSON_GetObjectItemCaseSensitive(current, "path")->valuestring);
+   }
+
+error:
+   cJSON_Delete(json);
+   return 1;
+}
diff --git a/src/libpgagroal/utils.c b/src/libpgagroal/utils.c
index 896e8ca1..d24064fa 100644
--- a/src/libpgagroal/utils.c
+++ b/src/libpgagroal/utils.c
@@ -1077,3 +1077,34 @@ parse_command_simple(int argc,
 {
    return parse_command(argc, argv, offset, command, subcommand, NULL, NULL, NULL, NULL);
 }
+
+/**
+ * Given a server state, it returns a string that
+ * described the state in a human-readable form.
+ *
+ * If the state cannot be determined, the numeric
+ * form of the state is returned as a string.
+ *
+ * @param state the value of the sate for the server
+ * @returns the string representing the state
+ */
+char*
+pgagroal_server_state_as_string(signed char state)
+{
+   char* buf;
+
+   switch (state)
+   {
+      case SERVER_NOTINIT:  return "Not init";
+      case SERVER_NOTINIT_PRIMARY: return "Not init (primary)";
+      case SERVER_PRIMARY: return "Primary";
+      case SERVER_REPLICA: return "Replica";
+      case SERVER_FAILOVER: return "Failover";
+      case SERVER_FAILED: return "Failed";
+      default:
+         buf = malloc(5);
+         memset(buf, 0, 5);
+         snprintf(buf, 5, "%d", state);
+         return buf;
+   }
+}