home - git - @ayo
= pgp = only used for releases
key - mit
7446 0D32 B808 10EB A9AF A2E9 6239 4C69 8C27 39FA

Cute decorative scissors, cutting through your code.

SQLBin Operational Manual


See the SQLBin homepage for the latest version and installation instructions.


Database preparation

I’m assuming you already have a PostgreSQL database running that you’d like to query against. You’ll want to setup a separate read-only user for SQLBin, because SQLBin by itself won’t prevent writes.

CREATE ROLE <user> LOGIN PASSWORD '<password>';

-- To grant read access to all tables:

-- Or to grant on a per-table basis
GRANT SELECT ON <public_table_name> TO <user>;

Permissions can be granted on individual tables, views, functions, columns and even rows. Refer to the PostgreSQL documentation for more information.

You can also set various configuration parameters for the user. The following are useful:

-- Change the default display of timestamptz values.
ALTER ROLE <user> SET timezone = 'UTC';
-- Set a default maximum query execution time.
ALTER ROLE <user> SET statement_timeout = '10 s';
-- Defense-in-depth, don't rely on this because it can likely be bypassed.
ALTER ROLE <user> SET default_transaction_read_only = true;

Configure SQLBin

Create a config.ini:


See the Configuration Directives below for the available settings. Then simply run SQLBin:

sqlbin -c /path/to/config.ini

Setup reverse proxy

For single-user mode you can point your browser directly to the bind socket of SQLBin, but to support multiple accounts you’ll need to put a proxy server in front that handles authentication and tells SQLBin which user is currently logged in.

Here’s a configuration example for nginx that queries another endpoint for authentication and then passes the user’s credentials to SQLBin. The endpoint response can set the X-USER-ID, X-USER-NAME and X-USER-ROLE headers. If these headers are not set, the default anonymous credentials are used instead.

# SQLBin passes state around in the URI, increasing the maximum request header size is recommended.
large_client_header_buffers 1 128k;

# Proxy this request to another endpoint to fetch user credentials.
# FastCGI or other handlers can also be used instead.
location = /auth-request-for-sqlbin {
  proxy_pass_request_body off;
  proxy_method GET;
  proxy_set_header Content-Length "";
  proxy_pass http://my-auth-endpoint/;  # <- Change this
auth_request /auth-request-for-sqlbin;

# Now grab the response headers from the above endpoint and pass them to SQLBin.
auth_request_set $auth_user_id   $upstream_http_x_user_id;
auth_request_set $auth_user_name $upstream_http_x_user_name;
auth_request_set $auth_user_role $upstream_http_x_user_role;
proxy_set_header X-USER-ID   $auth_user_id;
proxy_set_header X-USER-NAME $auth_user_name;
proxy_set_header X-USER-ROLE $auth_user_role;

proxy_pass;  # <- Point this to your SQLBin server

Don’t forget to add the following lines to SQLBin’s config.ini:


Configuration Directives



URI of the database being queried, formatted as postgresql://user:password@hostname/database. When connecting to a UNIX socket, use the following format: postgresql://user:password@/database?host=/path/to/socket.

SQLBin lets users run arbitrary queries over this connection, so it is important that the database user does not have more permissions than strictly necessary for querying.

Path where SQLBin can store data and cached queries. The directory will be created if it does not yet exist.

URI for the HTTP server to bind to, supported formats are tcp://ip:port/, unix:///path/to/socket or tls://ip:port?key=private.key&cert=certificate.cert&ca=ca.crt. While HTTPS is technically supported, you’ll probably still want to run SQLBin behind a reverse proxy anyway.

Defaults to tcp://


Path to the gnuplot-sqlbin binary for graphing functionality. See the gnuplot/ directory in the SQLBin source repository for instructions on how to build this binary.

While it is technically possible to use an unmodified gnuplot binary, doing so is wildly insecure and strongly discouraged. Regular gnuplot allows arbitrary shell execution, filesystem access and, for the use case of SQLBin, HTML injection, all of which the custom gnuplot-sqlbin build attempts to protect against.

How often to check whether a query is broken, in number of seconds. Defaults to 86400 (1 day), can be set to 0 to disable automatic checks.


SQLBin does not implement its own user management system, but instead expects that information about the current user is sent through HTTP request headers from a reverse proxy. Running in single-user mode (with or without a proxy) is also supported.

A “user” to SQLBin has only two properties: an id and a name. The id is case-sensitive, used in URLs and stored in the database and should be a stable identifier to uniquely identify a user. The name is only used for display purposes and does not have to be unique or stable.

User identifier to use when id_header not set or the header is not present in the request. Default “anonymous”.
Display name to use when name_header is not set or the header is not present in the request.

User role to assume when role_header is not set or the header is not present in the request. Only two roles are currently supported:

Regular user, can run queries and manage their own saved queries.
Administrator, can view private/unlisted queries and delete/edit queries of other users.

Any other value results in an internal server error.

Name of the HTTP request header to get the user id from, case-insensitive.
Name of the HTTP request header to get the display name from, case-insensitive.
Name of the HTTP request header to get the user’s role from, case-insensitive. See role_anon for supported values of this header.


SQLBin caches query results in order to provide a snappy user experience. Even if you prefer to always have fresh results from the database, caching queries for at least a few minutes will ensure that the UI remains somewhat responsive when working with slower queries.

Minimum time, in seconds, a query needs to take before it is considered for caching. The time is measured until the first row is received, which means it does not count any processing that the database may do in order to send further rows. Defaults to 0.05 (50 ms).
Number of seconds between scans through the cache to look for entries older than max_age. Defaults to 1800 (30 mins).
Number of seconds after which a cache entry is deleted. Cache entries are only checked once every check_interval, so it’s possible that older results are still used. Defaults to 3600 (1 hour).


Maximum number of query result rows to display in the HTML table. Defaults to 10k.
Maximum number of query result rows to pass to gnuplot. Defaults to 10k.
Maximum number of query result rows to include in the exports. Defaults to 100k.
Number of entries per page on the query browser. Defaults to 100.
Path to a HTML file to put on /about.