Connecting Metabase Cloud to Redshift fails and gives vague error

Hi there,

We're setting up Metabase Cloud and connecting it to our Redshift instance. After inputting all the information and whitelisting the IP addresses, we just get a vague error saying "An Error Occurred". The logs are posted below. Apologies if they're too long, wasn't sure which part exactly is needed for troubleshooting.

One hunch we have is that it's because the Redshift cluster isn't publicly accessible. However, we're confused cause our understanding was that it doesn't need to be publicly accessible (potentially a security risk) as long as IP's are whitelisted.

Here are the logs:

[673b2a52-263a-4e3e-a78d-509411cc2b50] 2022-05-25T11:36:46-07:00 INFO metabase.driver.impl Initializing driver :metabase.driver.sql-jdbc.execute.legacy-impl/use-legacy-classes-for-read-and-set...
[673b2a52-263a-4e3e-a78d-509411cc2b50] 2022-05-25T11:36:55-07:00 ERROR metabase.driver.util Database connection error
    java.util.concurrent.TimeoutException: Timed out after 10.0 s
    at metabase.util$deref_with_timeout.invokeStatic(util.clj:343)
    at metabase.util$deref_with_timeout.invoke(util.clj:335)
    at metabase.util$do_with_timeout.invokeStatic(util.clj:349)
    at metabase.util$do_with_timeout.invoke(util.clj:346)
    at metabase.driver.util$can_connect_with_details_QMARK_.invokeStatic(util.clj:47)
    at metabase.driver.util$can_connect_with_details_QMARK_.doInvoke(util.clj:36)
    at clojure.lang.RestFn.invoke(RestFn.java:442)
    at metabase.api.database$test_database_connection.invokeStatic(database.clj:431)
    at metabase.api.database$test_database_connection.doInvoke(database.clj:421)
    at clojure.lang.RestFn.invoke(RestFn.java:464)
    at metabase.api.setup$fn__74607.invokeStatic(setup.clj:169)
    at metabase.api.setup$fn__74607.invoke(setup.clj:160)
    at compojure.core$wrap_response$fn__32286.invoke(core.clj:160)
    at compojure.core$wrap_route_middleware$fn__32270.invoke(core.clj:132)
    at compojure.core$wrap_route_info$fn__32275.invoke(core.clj:139)
    at compojure.core$wrap_route_matches$fn__32279.invoke(core.clj:151)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$wrap_route_matches$fn__32279.invoke(core.clj:152)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$wrap_route_matches$fn__32279.invoke(core.clj:153)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298.invoke(core.clj:200)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298.invoke(core.clj:200)
    at compojure.core$make_context$handler__32326.invoke(core.clj:289)
    at compojure.core$make_context$fn__32330.invoke(core.clj:299)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:199)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:199)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298.invoke(core.clj:200)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:199)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298.invoke(core.clj:200)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298.invoke(core.clj:200)
    at metabase.api.routes$fn__77243$fn__77244.invoke(routes.clj:54)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298.invoke(core.clj:200)
    at clojure.lang.AFn.applyToHelper(AFn.java:160)
    at clojure.lang.AFn.applyTo(AFn.java:144)
    at clojure.core$apply.invokeStatic(core.clj:667)
    at clojure.core$apply.invoke(core.clj:662)
    at metabase.server.routes$fn__77388$fn__77389.doInvoke(routes.clj:57)
    at clojure.lang.RestFn.invoke(RestFn.java:436)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298.invoke(core.clj:200)
    at compojure.core$make_context$handler__32326.invoke(core.clj:289)
    at compojure.core$make_context$fn__32330.invoke(core.clj:299)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$wrap_route_matches$fn__32279.invoke(core.clj:153)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$wrap_route_matches$fn__32279.invoke(core.clj:153)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$wrap_route_matches$fn__32279.invoke(core.clj:153)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:199)
    at compojure.core$routes$fn__32298$f__32299$respond_SINGLEQUOTE___32300.invoke(core.clj:197)
    at compojure.core$make_context$fn__32330.invoke(core.clj:300)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298.invoke(core.clj:200)
    at compojure.core$routes$fn__32298$f__32299.invoke(core.clj:198)
    at compojure.core$routes$fn__32298.invoke(core.clj:200)
    at metabase.server.middleware.exceptions$catch_uncaught_exceptions$fn__74371.invoke(exceptions.clj:98)
    at metabase.server.middleware.exceptions$catch_api_exceptions$fn__74368.invoke(exceptions.clj:86)
    at metabase.server.middleware.log$log_api_call$fn__79455$fn__79456$fn__79457.invoke(log.clj:209)
    at metabase.driver.sql_jdbc.execute.diagnostic$do_with_diagnostic_info.invokeStatic(diagnostic.clj:15)
    at metabase.driver.sql_jdbc.execute.diagnostic$do_with_diagnostic_info.invoke(diagnostic.clj:9)
    at metabase.server.middleware.log$log_api_call$fn__79455$fn__79456.invoke(log.clj:201)
    at toucan.db$_do_with_call_counting.invokeStatic(db.clj:216)
    at toucan.db$_do_with_call_counting.invoke(db.clj:209)
    at metabase.server.middleware.log$log_api_call$fn__79455.invoke(log.clj:200)
    at metabase.server.middleware.browser_cookie$ensure_browser_id_cookie$fn__84848.invoke(browser_cookie.clj:38)
    at metabase.server.middleware.security$add_security_headers$fn__56133.invoke(security.clj:148)
    at metabase.server.middleware.json$wrap_json_body$fn__82159.invoke(json.clj:62)
    at metabase.server.middleware.json$wrap_streamed_json_response$fn__82177.invoke(json.clj:98)
    at metabase.server.middleware.offset_paging$handle_paging$fn__56157.invoke(offset_paging.clj:42)
    at ring.middleware.keyword_params$wrap_keyword_params$fn__85115.invoke(keyword_params.clj:55)
    at ring.middleware.params$wrap_params$fn__85131.invoke(params.clj:69)
    at metabase.server.middleware.misc$maybe_set_site_url$fn__34393.invoke(misc.clj:59)
    at metabase.server.middleware.session$bind_current_user$fn__46692$fn__46693.invoke(session.clj:262)
    at metabase.server.middleware.session$do_with_current_user.invokeStatic(session.clj:243)
    at metabase.server.middleware.session$do_with_current_user.invoke(session.clj:235)
    at metabase.server.middleware.session$bind_current_user$fn__46692.invoke(session.clj:261)
    at metabase.server.middleware.session$wrap_current_user_info$fn__46679.invoke(session.clj:221)
    at metabase.server.middleware.session$wrap_session_id$fn__46665.invoke(session.clj:167)
    at metabase.server.middleware.auth$wrap_api_key$fn__66126.invoke(auth.clj:27)
    at ring.middleware.cookies$wrap_cookies$fn__85035.invoke(cookies.clj:216)
    at metabase.server.middleware.misc$add_content_type$fn__34376.invoke(misc.clj:27)
    at metabase.server.middleware.misc$disable_streaming_buffering$fn__34401.invoke(misc.clj:76)
    at ring.middleware.gzip$wrap_gzip$fn__85077.invoke(gzip.clj:86)
    at metabase.server.middleware.misc$bind_request$fn__34404.invoke(misc.clj:93)
    at metabase.server.middleware.ssl$redirect_to_https_middleware$fn__84864.invoke(ssl.clj:48)
    at metabase.server$async_proxy_handler$fn__79228.invoke(server.clj:73)
    at metabase.server.proxy$org.eclipse.jetty.server.handler.AbstractHandler$ff19274a.handle(Unknown Source)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
    at org.eclipse.jetty.server.Server.handle(Server.java:516)
    at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:388)
    at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:633)
    at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:380)
    at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277)
    at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
    at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
    at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:338)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:315)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:173)
    at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131)
    at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:386)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034)
    at java.base/java.lang.Thread.run(Unknown Source)

Hi @absh
Metabase Cloud connects via the internet from these IP addresses: https://www.metabase.com/cloud/docs/ip-addresses-to-whitelist.html
So if your Redshift isn't accessible from the internet at all (inside VPC or some other local network), then it doesn't matter if you whitelist the IPs, since it's still not accessible.
Then you'll need to create an SSH bastion host, which Metabase Cloud can use to connect through.

Got it, thank you. Will try that right now. And yes those are the IP's we whitelisted. So the SSH is an alternative to having Redshift be publicly accessible? It will work even if it's private?

@absh You need to have something that is accessible from the internet if you use Metabase Cloud.
Otherwise you should self-host Metabase inside of your VPC or whatever private network you are in.

Makes sense. Can confirm that making the cluster public resolved the issue. Thank you for your help!