To automate a database with n8n, create a credential for Postgres, MySQL, Microsoft SQL, Oracle Database or MongoDB, then pair the database node with a trigger: a Schedule Trigger for reports and cleanup, the Postgres Trigger for new or changed rows, or a Webhook for events from your app. Pass values into SQL through the node's Query Parameters option, which n8n sanitizes against SQL injection, and connect with a database user that has only the permissions each workflow needs.
Checked against n8n's documentation and the n8n 2.41 release on October 1, 2026. This update replaces the January 2025 version, whose time-savings figures, execution times and database list we could not verify.
What n8n can do with a database
n8n works with databases through app nodes that run SQL or document operations as steps in a workflow. The jobs people automate most often:
- Scheduled reports: run a query every morning or week and send the result by email or Slack.
- Syncing: copy new or changed rows into a CRM, a spreadsheet or another database.
- Event reactions: start a workflow when a row is inserted, updated or deleted.
- Maintenance: archive or delete expired data in small, logged batches.
- Enrichment: read a record, call an API, and write the result back.
- AI lookups: let an AI agent read specific tables to answer questions.
Databases with built-in n8n nodes
| Database | n8n node | Operations |
|---|---|---|
| PostgreSQL | Postgres and Postgres Trigger | Select, Insert, Insert or Update, Update, Delete, Execute Query; trigger on insert, update or delete |
| MySQL | MySQL | Select, Insert, Insert or Update, Update, Delete, Execute SQL |
| Microsoft SQL Server | Microsoft SQL | Execute a query; insert, update and delete rows |
| Oracle Database 19c or later | Oracle Database | Select, Insert, Insert or Update, Update, Delete, Execute SQL |
| MongoDB | MongoDB | Aggregate, find, insert, update, find-and-update, find-and-replace and delete documents; manage search indexes |
| Warehouses and other stores | Snowflake, Google BigQuery, Databricks, Supabase, TimescaleDB, QuestDB, CrateDB, Redis, Elasticsearch, Azure Cosmos DB, Google Cloud Firestore | Varies by node |
Sources: n8n's Postgres, Postgres Trigger, MySQL, Microsoft SQL, Oracle Database and MongoDB node docs. Each of these five app nodes can also be connected to an AI agent as a tool.
For small amounts of data you do not want in your production database, such as dedupe markers or lookup lists, n8n's built-in Data tables need no external database at all. By default, all data tables in an instance share a 200 MiB limit, which self-hosted users can change with N8N_DATA_TABLES_MAX_SIZE_BYTES.
Step 1: Create a database user for n8n
Give n8n its own login with only the rights each workflow needs. For a reporting workflow on PostgreSQL, that means read-only access and a query timeout:
-- Read-only login for reporting workflows CREATE ROLE n8n_reporting LOGIN PASSWORD 'use-a-long-random-password'; GRANT CONNECT ON DATABASE app_db TO n8n_reporting; GRANT USAGE ON SCHEMA public TO n8n_reporting; GRANT SELECT ON ALL TABLES IN SCHEMA public TO n8n_reporting; -- Also cover tables created later by the role running this command ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO n8n_reporting; -- Stop runaway queries ALTER ROLE n8n_reporting SET statement_timeout = '30s';
ALL TABLES IN SCHEMA covers the tables that exist today, and the default-privileges line covers new ones; see PostgreSQL's GRANT and ALTER DEFAULT PRIVILEGES references. For workflows that write, create a second user with INSERT or UPDATE on only the tables that workflow touches. Keep every password in the n8n credential, never in a query or Code node.
Step 2: Add the credential in n8n
- Add a Postgres node to a workflow and create a new credential from its Credential to connect with field.
- Enter Host, Database, User, Password and Port. PostgreSQL listens on 5432 unless your provider says otherwise; MySQL uses 3306.
- Set SSL. n8n offers Allow, Disable and Require; use Require for any database reached over the internet and leave Ignore SSL Issues off.
- If the database is only reachable over SSH, turn on SSH Tunnel. n8n's credential docs say this works when an SSH server runs on the same machine as Postgres, and that the AI Agent node can't use SSH tunnels.
- Save, then run
SELECT 1with the Execute Query operation to confirm the connection before you build anything else.
Network access
- n8n Cloud: outbound requests come from the addresses on n8n's IP address list, and n8n recommends allowlisting all of them. The same page warns that "an IP allowlist alone doesn't prove a request came from your instance," because the addresses are shared, so keep SSL and a strong password as well.
- Self-hosted in Docker: inside a container,
localhostmeans the container, not your machine. Usehost.docker.internalas the host (on Linux, start n8n with--add-host host.docker.internal:host-gateway), or put both containers on one Docker network and use the database container's name. n8n's MySQL troubleshooting page walks through each setup.
Workflow 1: A scheduled SQL report by email
Four nodes: Schedule Trigger → Postgres (Execute Query) → HTML (Convert to HTML Table) → Gmail (Send).
- Schedule Trigger: set Trigger Interval to Weeks, Monday, 8am. The node uses the workflow's timezone if you set one in workflow settings, otherwise the instance timezone (America/New York by default on self-hosted n8n). Publish the workflow, or the schedule never runs.
- Postgres, Execute Query: run the query below.
- HTML, Convert to HTML Table: this operation turns every row into one item with a
tablefield. - Gmail, Send: set Email Type to HTML and Message to
{{ $json.table }}. The Gmail node appends "This email was sent automatically with n8n" by default; turn off Append n8n attribution in its options if you don't want it.
-- Last week's signups per day (example schema: users.created_at, users.plan)
SELECT
to_char(created_at::date, 'YYYY-MM-DD') AS day,
count(*) AS signups,
count(*) FILTER (WHERE plan <> 'free') AS paid_signups
FROM users
WHERE created_at >= date_trunc('week', now()) - interval '7 days'
AND created_at < date_trunc('week', now())
GROUP BY 1
ORDER BY 1;The to_char call is deliberate. n8n's Postgres troubleshooting page explains that the driver turns DATE values into full ISO datetimes, which can land on the wrong day in your timezone. Formatting the date in SQL keeps it as YYYY-MM-DD.
Workflow 2: Run a workflow when a row changes
The Postgres Trigger node starts a workflow on insert, update or delete events. Choose Listen and Create Trigger Rule, pick the table and event, and n8n creates a trigger and procedure when you publish the workflow, then removes them when you unpublish it. It can also Listen to Channel for notifications you send yourself.
The new row arrives as JSON under payload, so an order's ID is {{ $json.payload.id }} (check the trigger's output panel for your field names). Fetch the full record with a parameterized query:
SELECT o.id, o.total_amount, c.email
FROM orders o
JOIN customers c ON c.id = o.customer_id
WHERE o.id = $1;
-- Options > Query Parameters:
{{ [ $json.payload.id ] }}Then send the record where it needs to go (a CRM, Slack, an invoicing API) and mark it as processed with an Update operation. Know the limits first:
- Permissions: the credential's user needs superuser access, table ownership or the TRIGGER privilege, plus CREATE on the schema that holds the procedure. Use a separate user for this rather than your reporting login.
- Payload size: n8n's trigger sends the whole row through
pg_notify, and PostgreSQL's NOTIFY docs say the payload must be shorter than 8,000 bytes in the default configuration. Test with your widest rows before using it on tables with large text or JSON columns. - Delivery: a notification goes only to sessions that are listening when the transaction commits. If n8n is down or restarting, events are missed, so add a scheduled catch-up workflow that selects rows where
synced_at IS NULLand marks each one once it's handled.
n8n has no equivalent trigger node for MySQL, SQL Server, Oracle or MongoDB. Poll instead: run a Schedule Trigger every few minutes, select rows whose updated_at is later than the last run, and keep that timestamp in a Data table.
Workflow 3: Clean up old rows in small batches
-- Delete up to 5,000 expired sessions per run and report the count
WITH deleted AS (
DELETE FROM user_sessions
WHERE id IN (
SELECT id FROM user_sessions
WHERE last_activity < now() - interval '30 days'
LIMIT 5000
)
RETURNING id
)
SELECT count(*) AS deleted_rows FROM deleted;Schedule it hourly and post {{ $json.deleted_rows }} to Slack. Small batches keep locks short and make each run easy to audit. Before scheduling any delete, run the inner SELECT on its own to see what would go, and give the workflow a user that can delete from this one table only.
For riskier jobs, put a person in the loop: the Slack node's Send and Wait for Response operation, or Gmail's send-and-wait-for-approval operation, pauses the workflow until someone approves. When several writes must succeed together, set Query Batching to Transaction so Postgres rolls back all of them if one fails.
Write SQL that can't be injected
The most common mistake in n8n database workflows is dropping an expression straight into SQL:
-- Unsafe: a quote in the email can change the query
SELECT * FROM customers WHERE email = '{{ $json.email }}';Use placeholders and the Query Parameters option instead. n8n's Postgres and MySQL docs state that "n8n sanitizes data in query parameters, which prevents SQL injection."
-- Safe
SELECT id, email, plan FROM customers WHERE email = $1;
-- Options > Query Parameters:
{{ [ $json.email ] }}- Use
$1:namefor identifiers such as a table name, as in n8n's own exampleSELECT * FROM $1:name WHERE email = $2. - For
INlists, generate one placeholder per value and pass the array as the parameters. The Postgres troubleshooting page shows this pattern:
SELECT color, shirt_size FROM shirts
WHERE shirt_size IN ({{ $json.sizes.map((v, i) => '$' + (i + 1)).join(', ') }});
-- Options > Query Parameters:
{{ $json.sizes }}Where they fit, prefer the Select, Insert, Update and Insert or Update operations: they build the SQL for you from mapped columns.
Let an AI agent read your database
n8n's older SQL Agent is deprecated from n8n 1.82.0 and stops working in n8n 3.0, which n8n's breaking-changes page schedules for October 2026. The current approach is to connect a database node, such as Postgres, to the AI Agent node as a tool. The model can fill in tool parameters itself, or you can mark specific fields with $fromAI(). Guardrails that matter:
- Give the tool the read-only user from Step 1, with its statement timeout.
- Prefer the Select operation on a fixed table, with the model filling only the filter value, over letting it write free-form SQL:
{{ $fromAI('customer_email', 'Email address of the customer', 'string') }} - Set a row limit so one question can't pull a whole table into the prompt.
- Keep writes out of agent tools, or put an approval step in front of them.
- Log each question and the query it produced so you can review mistakes.
Performance and reliability
- Page through big tables. n8n's memory guide says it "doesn't restrict the amount of data each node can fetch and process," and suggests processing 200 rows per execution instead of 10,000, with Loop Over Items and sub-workflows.
- Choose Query Batching on purpose. Single Query sends one query for all items, Independently runs one per item, and Transaction rolls everything back on failure.
- Keep big numbers intact. Set Output Large-Format Numbers As to Text for
NUMERICorBIGINTvalues longer than 16 digits. The MySQL node returnsDECIMALvalues as strings by default to avoid precision loss. - Store times in UTC and set a workflow timezone for schedules.
- Add an error workflow. Build a workflow that starts with the Error Trigger node and sends an alert, then select it under Settings > Error workflow in each database workflow. It fires for automatic runs, not manual tests.
- Index what you filter on. Add indexes for columns in
WHEREandJOINclauses, and check slow queries with EXPLAIN.
Troubleshooting common errors
Connection refused or timeout
Check the host and port, the database firewall, and whether n8n runs in Docker (see Network access above). On n8n Cloud, confirm the database allows n8n's outbound IP addresses.
SSL errors
Managed databases usually require SSL, so pick Require. Use Ignore SSL Issues only for a short test, never in production.
The Postgres Trigger never fires
Make sure the workflow is published, the user can create triggers and procedures, and the row fits within the 8,000-byte notification limit.
Dates are a day off or big numbers look wrong
Format dates with to_char in SQL, and switch large-number output to Text.
The query works in my SQL client but returns nothing in n8n
Run it in the client as the same database user n8n uses, check that $1 maps to the first parameter value, and look at the node's input: expressions are evaluated per item.
When n8n isn't the right tool
n8n is strongest when database work connects to other apps: a report that lands in Slack, a new order that updates a CRM, an approval before a delete. For jobs that never leave the database, such as refreshing a summary table every night, a database-side scheduler like pg_cron is simpler. For moving millions of rows between warehouses, a dedicated ELT tool or the warehouse's own loaders are usually a better fit than item-by-item workflows.
Next steps
Start with one read-only report, add an error workflow, then move on to syncing and triggers. For the setup around it, see our guides to self-hosting n8n, n8n error handling, connecting any API with n8n and CRM automation, or browse the n8n workflow library. If you would rather build your own AI product than run client automations, AI SaaS Builder covers database design, Row Level Security, auth and edge functions in Supabase, along with the Claude API, Next.js and Stripe billing.
Want the full AI SaaS Builder playbook?
A 10-module, 52-lesson curriculum: validate an idea, build on Supabase and Next.js, add AI features with the Claude API, speed up with Claude Code and MCP, deploy on Vercel, launch, and charge with Stripe.
n8n database automation FAQ
Which databases does n8n support?
n8n has built-in nodes for PostgreSQL, MySQL, Microsoft SQL Server, Oracle Database (19c or later) and MongoDB, plus Snowflake, Google BigQuery, Databricks, Supabase, TimescaleDB, QuestDB, CrateDB, Redis, Elasticsearch, Azure Cosmos DB and Google Cloud Firestore. For light storage inside n8n itself, it also has Data tables.
How do I prevent SQL injection in n8n?
Do not paste expressions such as {{ $json.email }} straight into SQL. Write placeholders like $1 and $2 and pass the values in the Query Parameters option of the Postgres or MySQL node; n8n's docs say it sanitizes query parameters, which prevents SQL injection. Also connect with a database user that only has the permissions the workflow needs.
Can n8n start a workflow when a database row changes?
Yes for PostgreSQL. The Postgres Trigger node can create a trigger for insert, update or delete events on a table, or listen to a channel you notify yourself. The database user needs permission to create triggers and procedures. For MySQL, SQL Server, Oracle and MongoDB, poll on a schedule for rows changed since the last run.
Can n8n Cloud connect to my own database?
Yes, if the database accepts connections from the internet or through an SSH tunnel. Allowlist the n8n Cloud outbound IP addresses listed in n8n's docs, but because those addresses are shared across customers, still require SSL and a strong password.
Can an AI agent in n8n query my database?
Yes. Connect a database node such as Postgres to the AI Agent node as a tool, and the model fills in parameters itself or through $fromAI(). The older SQL Agent is deprecated from n8n 1.82.0 and stops working in n8n 3.0. Give the tool a read-only user with a statement timeout, and require human approval before any write.
How much data can an n8n workflow pull from a database?
n8n does not cap how much data a node fetches, so very large result sets can run out of memory. n8n's docs recommend processing smaller chunks, for example 200 rows per execution instead of 10,000, and moving heavy work into sub-workflows.