diff --git a/goatherd.go b/goatherd.go
index 34aa97c973d6931514208468c9a1fc4be54cbb46..426e17750fb3d890db717ad943b1e41f69e42a6c 100644
--- a/goatherd.go
+++ b/goatherd.go
@@ -13,6 +13,7 @@ import (
     "log"
     "net"
     "os"
+    "strings"
     "sync"
     "time"
 
@@ -162,11 +163,22 @@ func read_users_from_file(path string) {
         log.Fatalf("%v: group/other accessible, refusing operation\n", path)
     }
 
-    var users_want map[string]string
     f, err := os.Open(path)
     err_fatal(err)
-    err = json.NewDecoder(f).Decode(&users_want)
-    if err != nil { log.Fatalf("JSON decode %v: %v", path, err) }
+    lines := bufio.NewScanner(f)
+
+    users_want := make(map[string]string)
+    for lines.Scan() {
+        l := strings.TrimSpace(lines.Text())
+        if len(l) == 0 || l[0] == '#' {
+            continue
+        }
+        tokens := strings.SplitN(l, " ", 2)
+        if len(tokens) != 2 {
+            log.Fatalf("unexpected input in userlist: %v\n", l)
+        }
+        users_want[strings.TrimSpace(tokens[0])] = strings.TrimSpace(tokens[1])
+    }
 
     // update and delete existing users
     rows, err := db.Query("SELECT name, secret FROM users")
@@ -192,6 +204,7 @@ func read_users_from_file(path string) {
         } else {
             log.Printf("remove %v\n", have.name)
             _, err = db.Exec("DELETE FROM users WHERE name = $1", have.name)
+            err_fatal(err)
         }
     }