diff --git a/src/plugins/cpptools/cppcodecompletion.cpp b/src/plugins/cpptools/cppcodecompletion.cpp
index 174234f076754dcae26f08018612e58ae03e6d0b..f3c9a9d53fbb4436a522f2a0b52e74eb9ecea548 100644
--- a/src/plugins/cpptools/cppcodecompletion.cpp
+++ b/src/plugins/cpptools/cppcodecompletion.cpp
@@ -52,7 +52,6 @@
 
 #include <coreplugin/icore.h>
 #include <coreplugin/editormanager/editormanager.h>
-#include <coreplugin/mimedatabase.h>
 #include <texteditor/itexteditor.h>
 #include <texteditor/itexteditable.h>
 #include <texteditor/basetexteditor.h>
@@ -1216,29 +1215,13 @@ bool CppCodeCompletion::completeInclude(const QTextCursor &cursor)
         if (!includePaths.contains(currentFilePath))
             includePaths.append(currentFilePath);
 
-        const Core::MimeDatabase *mimeDatabase = Core::ICore::instance()->mimeDatabase();
-        const Core::MimeType mimeType = mimeDatabase->findByType(QLatin1String("text/x-c++hdr"));
-        const QStringList suffixes = mimeType.suffixes();
-
         foreach (const QString &includePath, includePaths) {
             QString realPath = includePath;
             if (!directoryPrefix.isEmpty()) {
                 realPath += QLatin1Char('/');
                 realPath += directoryPrefix;
             }
-            // TODO: This should be cached
-            QDirIterator i(realPath, QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
-            while (i.hasNext()) {
-                const QString fileName = i.next();
-                const QFileInfo fileInfo = i.fileInfo();
-                const QString suffix = fileInfo.suffix();
-                if (suffix.isEmpty() || suffixes.contains(suffix)) {
-                    QString text = fileName.mid(realPath.length() + 1);
-                    if (fileInfo.isDir())
-                        text += QLatin1Char('/');
-                    items.append(text);
-                }
-            }
+            items.append(m_manager->includesInPath(realPath));
         }
 
         if (!items.isEmpty()) {
diff --git a/src/plugins/cpptools/cppmodelmanager.cpp b/src/plugins/cpptools/cppmodelmanager.cpp
index f23fd06209fde0444058e51e4cd22999b6cd7485..c9c529983ca5553f0b947abf5a90d85ee2f4a6ff 100644
--- a/src/plugins/cpptools/cppmodelmanager.cpp
+++ b/src/plugins/cpptools/cppmodelmanager.cpp
@@ -701,6 +701,16 @@ QByteArray CppModelManager::internalDefinedMacros() const
     return macros;
 }
 
+void CppModelManager::setIncludesInPaths(const QMap<QString, QStringList> includesInPaths)
+{
+    QMutexLocker locker(&mutex);
+    QMapIterator<QString, QStringList> i(includesInPaths);
+    while (i.hasNext()) {
+        i.next();
+        m_includesInPaths.insert(i.key(), i.value());
+    }
+}
+
 void CppModelManager::addEditorSupport(AbstractEditorSupport *editorSupport)
 {
     m_addtionalEditorSupport.insert(editorSupport);
@@ -763,6 +773,23 @@ void CppModelManager::updateProjectInfo(const ProjectInfo &pinfo)
 
     m_projects.insert(pinfo.project, pinfo);
     m_dirty = true;
+
+    QFuture<void> result = QtConcurrent::run(&CppModelManager::updateIncludesInPaths,
+                                             this,
+                                             pinfo.includePaths,
+                                             m_headerSuffixes);
+
+    if (pinfo.includePaths.size() > 1) {
+        m_core->progressManager()->addTask(result, tr("Scanning"),
+                                           CppTools::Constants::TASK_INDEX,
+                                           Core::ProgressManager::CloseOnSuccess);
+    }
+}
+
+QStringList CppModelManager::includesInPath(const QString &path) const
+{
+    QMutexLocker locker(&mutex);
+    return m_includesInPaths.value(path);
 }
 
 QFuture<void> CppModelManager::refreshSourceFiles(const QStringList &sourceFiles)
@@ -1064,6 +1091,64 @@ void CppModelManager::onSessionUnloaded()
     GC();
 }
 
+void CppModelManager::updateIncludesInPaths(QFutureInterface<void> &future,
+                                            CppModelManager *manager,
+                                            QStringList paths,
+                                            QStringList suffixes)
+{
+    QMap<QString, QStringList> entriesInPaths;
+    int processed = 0;
+
+    future.setProgressRange(0, paths.size());
+
+    while (!paths.isEmpty()) {
+        if (future.isPaused())
+            future.waitForResume();
+
+        if (future.isCanceled())
+            break;
+
+        const QString path = paths.takeFirst();
+        QStringList entries;
+
+        QDirIterator i(path, QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
+        while (i.hasNext()) {
+            const QString fileName = i.next();
+            const QFileInfo fileInfo = i.fileInfo();
+            const QString suffix = fileInfo.suffix();
+            if (suffix.isEmpty() || suffixes.contains(suffix)) {
+                QString text = fileName.mid(path.length() + 1);
+                if (fileInfo.isDir()) {
+                    text += QLatin1Char('/');
+
+                    // Also scan subdirectory, but avoid endless recursion with symbolic links
+                    if (fileInfo.isSymLink()) {
+                        QMap<QString, QStringList>::const_iterator result = entriesInPaths.find(fileInfo.canonicalFilePath());
+                        if (result != entriesInPaths.constEnd()) {
+                            entriesInPaths.insert(fileName, result.value());
+                        } else {
+                            paths.append(fileName);
+                        }
+                    } else {
+                        paths.append(fileName);
+                    }
+                }
+                entries.append(text);
+            }
+        }
+
+        entriesInPaths.insert(path, entries);
+
+        ++processed;
+        future.setProgressRange(0, processed + paths.size());
+        future.setProgressValue(processed);
+    }
+
+    manager->setIncludesInPaths(entriesInPaths);
+
+    future.reportFinished();
+}
+
 void CppModelManager::parse(QFutureInterface<void> &future,
                             CppPreprocessor *preproc,
                             QStringList files)
diff --git a/src/plugins/cpptools/cppmodelmanager.h b/src/plugins/cpptools/cppmodelmanager.h
index a662618809e8db447ff80e11452d80ef2c53bbdd..e911971773e7a941702e5f7964293ab052042051 100644
--- a/src/plugins/cpptools/cppmodelmanager.h
+++ b/src/plugins/cpptools/cppmodelmanager.h
@@ -77,6 +77,8 @@ public:
     virtual ProjectInfo projectInfo(ProjectExplorer::Project *project) const;
     virtual void updateProjectInfo(const ProjectInfo &pinfo);
 
+    virtual QStringList includesInPath(const QString &path) const;
+
     virtual CPlusPlus::Snapshot snapshot() const;
     virtual void GC();
 
@@ -99,6 +101,9 @@ public:
     virtual void addEditorSupport(AbstractEditorSupport *editorSupport);
     virtual void removeEditorSupport(AbstractEditorSupport *editorSupport);
 
+    void setHeaderSuffixes(const QStringList &suffixes)
+    { m_headerSuffixes = suffixes; }
+
 Q_SIGNALS:
     void projectPathChanged(const QString &projectPath);
 
@@ -149,6 +154,13 @@ private:
     QStringList internalFrameworkPaths() const;
     QByteArray internalDefinedMacros() const;
 
+    void setIncludesInPaths(const QMap<QString, QStringList> includesInPaths);
+
+    static void updateIncludesInPaths(QFutureInterface<void> &future,
+                                      CppModelManager *manager,
+                                      QStringList paths,
+                                      QStringList suffixes);
+
     static void parse(QFutureInterface<void> &future,
                       CppPreprocessor *preproc,
                       QStringList files);
@@ -164,6 +176,9 @@ private:
     QStringList m_frameworkPaths;
     QByteArray m_definedMacros;
 
+    QMap<QString, QStringList> m_includesInPaths;
+    QStringList m_headerSuffixes;
+
     // editor integration
     QMap<TextEditor::ITextEditor *, CppEditorSupport *> m_editorSupport;
 
diff --git a/src/plugins/cpptools/cppmodelmanagerinterface.h b/src/plugins/cpptools/cppmodelmanagerinterface.h
index ce56686858137cbe9337a16e64b9d8a4dbb0c0ea..463e77a3679e8f7c858720f2fe7641653074a732 100644
--- a/src/plugins/cpptools/cppmodelmanagerinterface.h
+++ b/src/plugins/cpptools/cppmodelmanagerinterface.h
@@ -90,6 +90,8 @@ public:
     virtual ProjectInfo projectInfo(ProjectExplorer::Project *project) const = 0;
     virtual void updateProjectInfo(const ProjectInfo &pinfo) = 0;
 
+    virtual QStringList includesInPath(const QString &path) const = 0;
+
     virtual void addEditorSupport(AbstractEditorSupport *editorSupport) = 0;
     virtual void removeEditorSupport(AbstractEditorSupport *editorSupport) = 0;
 };
diff --git a/src/plugins/cpptools/cpptoolsplugin.cpp b/src/plugins/cpptools/cpptoolsplugin.cpp
index 30858508d44059a7ed05351620c000453196db2f..210419b92083281f1010957c5e61276cef7efad1 100644
--- a/src/plugins/cpptools/cpptoolsplugin.cpp
+++ b/src/plugins/cpptools/cpptoolsplugin.cpp
@@ -263,6 +263,11 @@ void CppToolsPlugin::extensionsInitialized()
     m_fileSettings->fromSettings(Core::ICore::instance()->settings());
     if (!m_fileSettings->applySuffixesToMimeDB())
         qWarning("Unable to apply cpp suffixes to mime database (cpp mime types not found).\n");
+
+    // Initialize header suffixes
+    const Core::MimeDatabase *mimeDatabase = Core::ICore::instance()->mimeDatabase();
+    const Core::MimeType mimeType = mimeDatabase->findByType(QLatin1String("text/x-c++hdr"));
+    m_modelManager->setHeaderSuffixes(mimeType.suffixes());
 }
 
 void CppToolsPlugin::shutdown()