diff --git a/connections/aws-iam.mdx b/connections/aws-iam.mdx
index feb0651a..51c65715 100644
--- a/connections/aws-iam.mdx
+++ b/connections/aws-iam.mdx
@@ -105,6 +105,10 @@ mydb.abc123.us-east-1.rds.amazonaws.com:5432
The port is optional, falling back to 5432 for PostgreSQL and 3306 for MySQL and MariaDB. The field also covers a CNAME or any alias AWS did not issue, and is honored only when **Host** is loopback or already the same hostname.
+## Redshift
+
+Redshift hands out its own user and temporary password rather than a signed token. The same three options appear on a Redshift connection, and [Redshift](/databases/redshift#aws-iam-sign-in) covers what each endpoint calls.
+
## On iPhone and iPad
Synced connections keep their AWS IAM option. **AWS IAM (Profile)** needs an access key saved on the device, and **AWS IAM (SSO)** signs in to IAM Identity Center from the device itself. [IAM sign-in](/ios#iam-sign-in) covers the setup.
diff --git a/connections/connection-form.mdx b/connections/connection-form.mdx
index f36c71f0..aaa71426 100644
--- a/connections/connection-form.mdx
+++ b/connections/connection-form.mdx
@@ -70,7 +70,9 @@ Encryption sits below the transport. [SSL/TLS](/connections/ssl) covers the mode
| **Connect timeout** | Maximum seconds for the network transport and remote database to finish connecting. Empty uses 30 seconds; valid values are 1 to 600 |
| **Query timeout** | Override of **Settings > General** for this connection. Empty inherits the global value; `0` means no limit. Only drivers that support query timeouts enforce it |
| **Startup Commands** | SQL to run after every connect. See [Startup commands](#startup-commands) |
-| **Pre-Connect Script** | Shell script run before connecting. A non-zero exit aborts the connect |
+| **Pre-Connect Script** | Shell script run before connecting. A non-zero exit aborts the connect. See [Connection scripts](#connection-scripts) |
+| **Timeout** | Seconds each connection script may run. Empty uses 10; valid values are 1 to 300 |
+| **Post-Disconnect Script** | Shell script run once the session ends, after a pre-connect script ran. See [Connection scripts](#connection-scripts) |
| **Safe Mode** | Confirms, authenticates or refuses queries before they run. See [Safe Mode](/features/safe-mode) |
| **AI Policy** | Per-connection override for the in-app AI agents. **Never** also refuses external clients. Shown while **Enable AI Features** is on |
| **External Clients** | **Blocked**, **Read Only** (the default), or **Read & Write** for MCP clients such as Raycast, Cursor, and Claude Desktop, and for [AppleScript](/developers/applescript). A token's own scope cannot raise it. See the [integration security model](/developers#security-model) |
@@ -88,10 +90,6 @@ session picks it up.
-A pre-connect script never runs unprompted. A **Pre-Connect Script** alert shows the script itself and waits for **Run Script**, every time, whatever opens the connection: its window, a link, Compare, **Copy To**, the AI assistant, an MCP client or a script. With no answer in 60 seconds the alert closes as **Cancel**.
-
-A connect you did not start never runs the script. A restored window at launch, a table loading on its own and a reconnect after a tunnel drops all stop at a **Connect** button instead.
-
## Appearance
**Icon** replaces the database logo in the connection list, **Switch Connection**, the connections strip and the toolbar. Click it, type to search the symbols, then click one or press `Return`. **Default** brings the logo back. The database type stays in the row's tooltip.
@@ -115,6 +113,39 @@ SET search_path TO myschema, public;
A statement that fails is logged and skipped, and the connection still opens.
+## Connection scripts
+
+Put whatever has to happen before the database answers in **Pre-Connect Script**: a VPN profile coming up, `aws sso login`, a credential refresh. The script runs in `bash`, and a non-zero exit stops the connect with the script's standard error in the message. Homebrew's `/opt/homebrew/bin` and `/usr/local/bin` are on `PATH` even when TablePro was opened from the Dock.
+
+Both scripts get the connection in their environment, so one script can serve every connection that needs it:
+
+| Variable | Value |
+|---|---|
+| `TABLEPRO_CONNECTION_NAME` | The connection's name |
+| `TABLEPRO_HOST` | **Host**, as typed, even when an SSH tunnel or proxy carries the connection |
+| `TABLEPRO_PORT` | **Port**, as typed |
+| `TABLEPRO_USER` | **Username**, or the linked credential profile's |
+| `TABLEPRO_DATABASE` | **Database** |
+
+The password is never passed.
+
+```bash
+scutil --nc start "Office VPN"
+until nc -z "$TABLEPRO_HOST" "$TABLEPRO_PORT"; do sleep 1; done
+```
+
+A script still running at **Timeout** is stopped and the connect fails. Raise it for a VPN that takes 15 seconds to come up or a sign-in that waits on the browser. Canceling the connect stops the script too.
+
+**Post-Disconnect Script** undoes what the pre-connect script started. It runs once per session, after the session ends by **Disconnect**, by closing its last window, by quitting TablePro, or by a connect that fails after the pre-connect script succeeded. A connection with no pre-connect script never runs it. It gets the same variables and the same timeout, and a failure goes to the log rather than an alert.
+
+```bash
+scutil --nc stop "Office VPN"
+```
+
+Neither script runs unprompted. A **Pre-Connect Script** alert shows both scripts and waits for **Run Script**, every time, whatever opens the connection: its window, a link, Compare, **Copy To**, the AI assistant, an MCP client or a script. With no answer in 60 seconds the alert closes as **Cancel**.
+
+A connect you did not start never runs the script. A restored window at launch, a table loading on its own and a reconnect after a tunnel drops all stop at a **Connect** button instead. Links, exports and the Team Library carry neither script.
+
## Connection health
Every active connection is checked on the interval set by **Check connections** in Settings >
diff --git a/connections/credential-profiles.mdx b/connections/credential-profiles.mdx
index a5e08c4f..3da9a72e 100644
--- a/connections/credential-profiles.mdx
+++ b/connections/credential-profiles.mdx
@@ -49,6 +49,18 @@ A linked connection keeps no password of its own. Linking deletes the one it had
Pick **Saved in the Keychain** unless something else already owns the password. **Read from elsewhere** never leaves this Mac and never syncs.
+### A command that works for every connection
+
+**The output of a command** runs in `bash` for whichever connection is opening. Write `{host}`, `{port}`, `{user}` and `{database}` where the command needs them, and each becomes that connection's value as one quoted word, with or without quotes around the placeholder. The same values arrive as `TABLEPRO_HOST`, `TABLEPRO_PORT`, `TABLEPRO_USER` and `TABLEPRO_DATABASE`, plus `TABLEPRO_CONNECTION_NAME`.
+
+```bash
+aws rds generate-db-auth-token --hostname {host} --port {port} --username {user}
+```
+
+`{host}` and `{port}` are the ones typed in the form, never the local port of a tunnel. `${host}` is left for `bash`.
+
+**Reuse Result For** keeps the output for 5 minutes, 15 minutes, an hour or 8 hours, so a reconnect inside that window skips the command. Set it below the lifetime of whatever the command prints. The output stays in memory, and a connect that fails throws it away so the next one runs the command again.
+
## Additional secrets
Some engines sign in with more than a password: an AWS secret access key, a Snowflake private key, a service account JSON. **Additional Secrets** in the profile editor lists them per database type. A connection reads only the secrets its own type declares, so one profile can carry several engines' keys without them colliding.
diff --git a/databases/redshift.mdx b/databases/redshift.mdx
index b5761593..2fbc05d2 100644
--- a/databases/redshift.mdx
+++ b/databases/redshift.mdx
@@ -15,9 +15,21 @@ Redshift speaks the PostgreSQL wire protocol and uses the same bundled libpq dri
Fill in the form and click **Save & Connect**. New connections default to SSL mode **Preferred**, and there is no version gate: any cluster AWS still runs will connect.
-
-AWS IAM authentication is not available for Redshift connections, unlike MySQL and PostgreSQL. Use a database username and password. For a cluster that is not publicly reachable, put it behind an [SSH tunnel](/connections/ssh-tunneling) on a bastion in the VPC.
-
+For a cluster that is not publicly reachable, put it behind an [SSH tunnel](/connections/ssh-tunneling) on a bastion in the VPC.
+
+## AWS IAM sign-in
+
+Set **Authentication** to **AWS IAM (Profile)**, **AWS IAM (SSO)** or **AWS IAM (Access Key)**, and every connect asks AWS for a user and a temporary password instead of reading a saved one. Profiles resolve as described in [AWS IAM Authentication](/connections/aws-iam#profiles), IAM Identity Center sign-in included.
+
+| Endpoint | AWS call | Signs in as |
+|---|---|---|
+| Provisioned cluster, **Username** empty | `redshift:GetClusterCredentialsWithIAM` | The user mapped to your IAM identity, such as `IAMR:analyst` |
+| Provisioned cluster, **Username** set | `redshift:GetClusterCredentials` for that user | `IAM:` and the user name |
+| Serverless workgroup | `redshift-serverless:GetCredentials` | The user mapped to your IAM identity |
+
+The cluster or workgroup and its region come from **Host**, so keep it the endpoint AWS issued. A tunnel TablePro opens needs nothing more. A port forward you run yourself leaves `127.0.0.1` in **Host**: set **Redshift Endpoint** to the real one, such as `my-cluster.abc123xyz.us-east-1.redshift.amazonaws.com`. It is honored only when **Host** is a loopback address or that same endpoint. **AWS Region** overrides the region.
+
+The policy needs the call above on the cluster or workgroup, and access to the `dbname` when it limits databases. The password lasts 15 minutes and is fetched again for each connect, and SSL mode **Disabled** or **Preferred** is raised to **Required**. IAM sign-in to Redshift works on the Mac only.
## Connection URL
diff --git a/features/connection-sharing.mdx b/features/connection-sharing.mdx
index 4d08e951..0bf57cdb 100644
--- a/features/connection-sharing.mdx
+++ b/features/connection-sharing.mdx
@@ -83,7 +83,7 @@ Group and folder paths match by name from the top down: an existing group or fol
-Anything that decides where a credential comes from is stripped on the way in, from a file and from a link alike: AWS options including IAM authentication, the region, the profile and the RDS endpoint; **Use Password File**; **Prompt for password**; the SSL client key passphrase; the pre-tunnel host and port; and the **Pre-Connect Script**. Startup SQL and tunnel commands run on every connect, so a file brings them only if you agree: importing lists each one and asks, and **Import Without Commands** is the default. A link's sheet shows its startup SQL in full before you add it.
+Anything that decides where a credential comes from is stripped on the way in, from a file and from a link alike: AWS options including IAM authentication, the region, the profile and the RDS endpoint; **Use Password File**; **Prompt for password**; the SSL client key passphrase; the pre-tunnel host and port; and the **Pre-Connect Script** and **Post-Disconnect Script**. Startup SQL and tunnel commands run on every connect, so a file brings them only if you agree: importing lists each one and asks, and **Import Without Commands** is the default. A link's sheet shows its startup SQL in full before you add it.
## Share via link
@@ -160,6 +160,7 @@ A connection in `~/Library/Application Support/TablePro/connections.json` can sa
{ "passwordSource": { "kind": "file", "path": "~/.config/tablepro/secrets/feature-x.pw" } }
{ "passwordSource": { "kind": "env", "variable": "STAGING_DB_PASSWORD" } }
{ "passwordSource": { "kind": "command", "shell": "op read op://vault/feature-x/password" } }
+{ "passwordSource": { "kind": "command", "shell": "aws rds generate-db-auth-token --hostname {host} --port {port} --username {user}", "reuseSeconds": 600 } }
{ "passwordSource": { "kind": "onePassword", "reference": "op://vault/feature-x/password" } }
{ "passwordSource": { "kind": "vault", "path": "secret/data/staging/db", "field": "password" } }
{ "passwordSource": { "kind": "awsSecretsManager", "secretId": "prod/db", "jsonKey": "password" } }
@@ -169,7 +170,7 @@ A connection in `~/Library/Application Support/TablePro/connections.json` can sa
|---|---|---|
| `file` | The file at `path`, minus a trailing newline | `chmod 600` the file |
| `env` | The named environment variable | Same Dock caveat as environment variables |
-| `command` | stdout of the command, run through `/bin/bash`. A non-zero exit fails the connect | |
+| `command` | stdout of the command, run through `/bin/bash`, with `{host}`, `{port}`, `{user}` and `{database}` filled in and quoted. A non-zero exit fails the connect. `reuseSeconds`, 1 to 86400, keeps the output that long | |
| `onePassword` | `op read` on the reference | `op signin` |
| `vault` | `vault kv get` for one field at a path | `VAULT_ADDR` and `VAULT_TOKEN` in TablePro's environment |
| `awsSecretsManager` | `aws secretsmanager get-secret-value`. `jsonKey` pulls one field out of a JSON secret; omit it for the whole value | |